IT

로직을 추가 할 MVC (Laravel)

lottoking 2020. 7. 22. 07:49
반응형

로직을 추가 할 MVC (Laravel)


CRUD 작업을 수행하거나 특정 방식으로 수행 할 때마다 다른 작업을 수행 가정 해 보겠습니다. 예를 들어 누군가가 게시물을 게시 할 때마다 분석을 위해 테이블에 추가하려고합니다. 아마도 가장 좋은 예는 일반적 으로이 "그룹화 된"기능이 많이 있습니다.

일반적으로 정상의 논리가 컨트롤러에 적용됩니다. 이 기능을 많은 곳에서 재현하고 싶을 때 괜찮습니다. 더미 컨텐츠를 생성하기 시작하면 DRY를 유지하는 데 문제가 발생합니다.

이를 관리하는 방법은 이벤트, 리포지토리, 라이브러리 및 모델에 추가하는 것입니다. 각각에 대한 나의 이해는 다음과 가변적입니다.

서비스 : 대부분의 사람들이 코드를 넣을 수있는 곳입니다. 서비스의 주요 문제는 특정 기능을 찾기 어렵고 사람들이 Eloquent를 사용하는 데 집중할 때 잊어 버린 것입니다. publishPost()내가 할 수있을 때 라이브러리에서 메소드를 호출해야한다는 것을 어떻게 알 $post->is_published = 1있습니까?

내가 잘 작동하는 유일한 조건은 서비스 만 사용하는 것입니다 (이상적으로 컨트롤러에서 Eloquent에 액세스 할 수있는 것이라는 것입니다).

광고로 요청이 일반적으로 모델 구조를 따르는 경우 추가 파일을 많이 생성하는 것처럼 보입니다.

리포지토리 : 내가 이해 한 바에 따르면 기본적으로 기본적으로 서비스와 추가해야 할 인터페이스가 있으므로 또는 M간에 전환 할 수 있습니다.

이벤트 : 모델 이벤트가 항상 Eloquent 메소드에서 호출부터 컨트롤러처럼 컨트롤러를 호출 수 있기 때문에 가장 우아한 시스템이라고 생각합니다. 나는 이것들이 지저분 해지는 것을 볼 수 있고 중요한 커플 링을위한 이벤트를 사용하는 하나의 프로젝트의 예를 가지고있는 것이보고 싶습니다.

모델 : 전통적으로 CRUD를 수행하고 임계 커플 링을 처리하는 클래스가 함수. CRUD +와 관련된 모든 기능을 알고 있었기 때문에 실제로는 일을 쉽게했습니다.

간단하지만 MVC 아키텍처에서는 일반적으로 내가 본 것이 아닙니다. 어떤 점에서는 찾기가 더 제부 추적 할 파일이 적기 때문에 서비스보다 선호합니다. 그래도 약간 혼란 스러울 수 있습니다. 이 방법에 대한 몰락과 대부분의 사람들이 왜 그렇게하지 않는지 듣고 싶습니다.

각 방법의 장단점은 무엇입니까? 뭔가 빠졌습니까?


SOLID 원칙 을 따르는 한 모든 패턴 / 아키텍처가 매우 유용하다고 생각합니다 .

논리를 추가위치에 있는 단일 책임 원칙 을 참조하는 것이 중요하다고 생각합니다 . 또한 제 대답은 당신이 중형 / 대형 프로젝트를 진행하고 생각합니다. 그것이 페이지에 던지는 일 이라면 ,이 답변을 잊어 버리고 컨트롤러 나 모델에 모두 추가하십시오.

짧은 대답은 : 그것은 (서비스) 당신에게 의미가 어디 .

긴 대답 :

컨트롤러 : 컨트롤러 의 책임은 무엇입니까? 물론 모든 논리를 컨트롤러에 넣을 수 있습니다. 나는 그렇게 생각하지 않습니다.

나를 위해 컨트롤러는 요청을 받고 데이터를 반환해야하며이 유효성 검사를하거나 db 메소드를 호출하는 장소가 아닙니다.

모델 : 사용자가 게시물의 투표 수를 등록하거나 업데이트 할 때 환영 이메일 보내기와 같은 논리를 추가 할 때 좋은 장소입니까? 코드의 다른 곳에서 동일한 이메일을 보내야한다면 어떻게해야합니까? 정적 메소드를 작성합니까? 해당 이메일에 다른 모델의 정보가 필요한 경우 어떻게됩니까?

모델이 작성을 작성해야합니다. Laravel으로, 나는 단지 같은 것들을 추가하는 모델 클래스 를 사용 fillable, guarded, table(다른 모델도있을 것입니다, 나는 저장소 패턴을 사용하기 때문에 이과 의 관계를 save, update, find, 등의 방법).

리포지토리 (리포지토리 패턴) : 처음에 나는 이것으로 매우 혼란 스러웠습니다. 그리고 당신처럼, 저는 "저는 MySQL을 사용합니다."라고 생각했습니다.

그러나 리포지토리 패턴은 사용의 장단점을 균형있게 사용하여 이제는 사용합니다. 나는 지금순간 에 MySQL 만 사용하면 된다고 생각한다 . 그러나 3 년 후에 MongoDB와 같은 작업이 완료됩니다. 하나의 추가 인터페이스와 $app->bind(«interface», «repository»).

이벤트 ( 관찰자 패턴 ) : 이벤트는 주어진 시간에 어떤 클래스에서든 던질 수있는 것들에 유용합니다. 예를 들어, 사용자에게 알림을 생각하십시오. 필요할 때 응용 프로그램의 모든 클래스에서 알림을 보내도록 이벤트를 시작합니다. 그런 다음 UserNotificationEvents사용자 알림을 위해 시작된 모든 이벤트를 처리 하는 클래스를 만들 수 있습니다 .

서비스 : 지금까지 컨트롤러 나 모델에 추가 할 수 있습니다. 나에게 서비스 유전자를 추가하는 것이 모든 의미가있다 . 서비스는 클래스의 멋진 이름입니다. 그리고 당신은 당신이 당신의 응용 프로그램 내에서 당신이 이해하는만큼 많은 수업을 수 있습니다.

이 예를 보자. 얼마 전, 나는 구글 폼과 같은 것을 개발했다. 시작 나는 CustomFormService과 함께 결국 CustomFormService, CustomFormRender, CustomFieldService, CustomFieldRender, CustomAnswerServiceCustomAnswerRender. 왜? 이해가 되었기 때문입니다. 팀과 함께 작업하는 경우 팀에 있어야 위치에 논리를 배치합니다.

서비스 대 컨트롤러 / 모델 사용의 단일 한 컨트롤러 또는 단일 모델에 의해 제한을받지 않는다는 것입니다. 응용 프로그램의 디자인과 요구에 따라 필요한만큼의 서비스를 만들 수 있습니다. 응용 프로그램의 모든 클래스 내에서 서비스를 호출하면 이점이 있습니다.

이것은 오래 걸리지 만 응용 프로그램을 어떻게 구성했는지 보여주고 있습니다.

app/
    controllers/
    MyCompany/
        Composers/
        Exceptions/
        Models/
        Observers/
        Sanitizers/
        ServiceProviders/
        Services/
        Validators/
    views
    (...)

특정 기능을 위해 각 폴더를 사용합니다. 예를 들어, Validators디렉토리에는 특정 유효성 검사기 특정 유효성 검사기 (일반적으로 각 모델마다 하나씩)를 BaseValidator기반으로 유효성 검사를 처리 하는 클래스 가 포함되어 있습니다 . 이 코드를 서비스에 쉽게 넣을 수는 서비스 내에서 사용 가능합니다.$rules$messages

다음 기사를 읽어들입니다. 내용이 조금 더 잘 설명 될 수 있습니다.

Dayle Rees (CodeBright의 저자)에 의한 틀 깨기 : 이것은 내가 필요에 맞게 몇 가지 사항을 변경 했음에도 불구하고 모든 것을 한 곳에 모은 곳입니다.

Chris Goosey의 리포지토리 및 서비스사용하여 Laravel에서 코드 분리 :이 게시물에서는 서비스 및 리포지토리 패턴과 함께 방식에 대해 설명합니다.

라라 캐스트에는 리포지토리 단순화단일 책임 이 많은 실제 사례를 통해 훌륭한 리소스를 제공합니다 (비용을 지불해야합니다).


내 질문에 대한 답변을 게시하고 싶었습니다. 나는 이것에 대해 며칠 동안 이야기 할 수 있도록 빨리 올리기 위해 노력할 것입니다.

Laravel이 제공하는 기존 구조를 사용하여 결국 파일을 기본적으로 모델, 뷰 및 컨트롤러로 유지했습니다. 또한 실제로 모델링되지 않은 추가 구성 요소에 대한 라이브러리 폴더도 있습니다.

서비스 / 라이브러리에서 내 모델을 래핑하지 않습니다 . 모든 이유가 100 % 서비스 사용의 이점을 보장하지. 내가 틀릴 수도 있고, 내가 볼 수있는 한, 모델로 작업 할 때 만들고 전환해야하는 엄청난 양의 매의 파일이 생성되고 웅변 사용의 이점을 실제로 줄입니다 (모델 모델 복구와 관련하여) 범위 등을 사용).

비즈니스를 모델에 컨트롤러 에서 직접 웅변 적으로 액세스합니다. 관리하지 않는 우회 방식을 사용하지 않습니다.

  • 접근 자와 뮤 테이터 : 라 라벨에는 훌륭한 접근 자와 뮤 테이터가 있습니다. 게시물이 초안에서 게시로 실행할 때마다 작업을 수행 한 결과 setIsPublishedAttribute 함수를 작성하고 거기에 논리를 포함 시켜서 호출 할 수 있습니다.
  • 작성 / 업데이트 등 재정의 : 사용자 정의 기능을 포함하도록 모델에서 항상 Eloquent 메소드를 재정의 할 수 있습니다. 이렇게하면 모든 CRUD 작업에서 기능을 호출 할 수 있습니다. 편집 : 최신 Laravel 버전에서 생성을 재정의하는 데 버그가 문제가 있다고 생각합니다 (부트에 등록 된 이벤트를 사용합니다).
  • 유효성 검사 :

    유효성 검사를 같은 방식으로 연결합니다. 예를 들어 CRUD 함수를 재정렬 유효성 검사를 실행하고 필요한 경우 접근 자 / 돌연변이도 실행합니다. 자세한 내용은 Esensi 또는 dwightwatson / validating을 참조하십시오.
  • 매직 메소드 : 모델의 __get 및 __set 메소드를 사용하여 적절한 경우 기능에 연결
  • Eloquent 확장 : 모든 업데이트 / 생성 작업을 수행하려는 경우 웅변을 확장 하여 여러 모델에 적용 할 수도 있습니다.
  • 사건 : 이것은 솔직한 일반적으로 제공하기 위해 처리 된 장소입니다. 이벤트의 가장 큰 단점은 예외를 추적하기 어렵다는 것입니다 (Laravel의 새로운 이벤트 시스템에서는 새로운 경우가 아닐 수도 있습니다). 또한 전화를받을 때 대신에하는 일을 기준으로 내 이벤트를 그룹화하고 싶습니다. 예를 들어, 메일을 수신하는 MailSender 가입자가 있습니다.
  • 피벗 / 소속 된 ToMany 이벤트 추가 : 내가 가장 오랫동안 고민 한 것 중 하나는 소속 된 ToMany 관계의 수정에 동작을 추가하는 방법. 예를 들어, 사용자가 그룹에 참여할 때마다 작업을 수행합니다. 나는 관리를 위해 커스텀 라이브러리를 다듬었다. 아직 게시하지 기능적입니다! 곧 링크를 게시합니다. 편집 나는 모든 피벗을 일반 모델로 만들고 결국 내 인생이 지금부터 ...

모델 사용에 대한 사람들의 우려를 해결 :

  • 조직 :. 모델에 더 많은 것들이 포함하면 더 길어질 수 있습니다. 모델의 75 %가 여전히 작습니다. 더 큰 것을 구성하기로 선택한 경우 특성을 사용하여 수행 할 수 있습니다 (예 : 필요에 따라 PostScopes, PostAccessors, PostValidation 등의 파일이 더 많은 모델의 폴더 만들기). 나는 이것이 반드시 필요한 것이 있어야한다는 것을 알고 있습니다.

추가 참고 사항 : 스위스 군용 칼을 가지고 많은 도구를 사용하고 기본적으로 똑같은 일을하는 다른 칼을 만드는 서비스가 있습니다. 예, 블레이드 블레이드를 테이핑하거나 두 개의 블레이드 블레이드를 함께 사용하고 싶을 수도 있습니다.

서비스를 사용하는 경우 :이 기사는 서비스를 사용하는시기에 대한 훌륭한 예제를 보여줍니다 ( 힌트 : 자주는 아님). 기본적으로 의미가 수명주기의 이상한 부분에서 여러 모델을 사용할 때 의미가 있습니다. http://www.justinweiss.com/articles/where-do-you-put-your-code/


컨트롤러와 모델 논리를 만드는 데 사용하는 것은 서비스 계층 을 만드는 것 입니다. 기본적으로는 내 앱 내의 모든 작업에 대한 흐름입니다.

  1. 컨트롤러는 사용자의 요청 된 조치를 수신하는 서비스 변수를 전송하고 모든 것을 전달합니다.
  2. 서비스 클래스는 입력 유효성 검사, 이벤트 로깅, 데이터베이스 작업 등 작업과 관련된 모든 논리를 수행합니다.
  3. 모델은 필드 정보, 데이터 변환 및 속성 정의를 보유합니다.

이것이 내가하는 방법입니다.

이 방법을 만드는 컨트롤러의 방법입니다.

public function processCreateCongregation()
{
    // Get input data.
    $congregation                 = new Congregation;
    $congregation->name           = Input::get('name');
    $congregation->address        = Input::get('address');
    $congregation->pm_day_of_week = Input::get('pm_day_of_week');
    $pmHours                      = Input::get('pm_datetime_hours');
    $pmMinutes                    = Input::get('pm_datetime_minutes');
    $congregation->pm_datetime    = Carbon::createFromTime($pmHours, $pmMinutes, 0);

    // Delegates actual operation to service.
    try
    {
        CongregationService::createCongregation($congregation);
        $this->success(trans('messages.congregationCreated'));
        return Redirect::route('congregations.list');
    }
    catch (ValidationException $e)
    {
        // Catch validation errors thrown by service operation.
        return Redirect::route('congregations.create')
            ->withInput(Input::all())
            ->withErrors($e->getValidator());
    }
    catch (Exception $e)
    {
        // Catch any unexpected exception.
        return $this->unexpected($e);
    }
}

작업과 관련된 논리를 수행하는 서비스 클래스입니다.

public static function createCongregation(Congregation $congregation)
{
    // Log the operation.
    Log::info('Create congregation.', compact('congregation'));

    // Validate data.
    $validator = $congregation->getValidator();

    if ($validator->fails())
    {
        throw new ValidationException($validator);
    }

    // Save to the database.
    $congregation->created_by = Auth::user()->id;
    $congregation->updated_by = Auth::user()->id;

    $congregation->save();
}

그리고 이것은 내 모델입니다.

class Congregation extends Eloquent
{
    protected $table = 'congregations';

    public function getValidator()
    {
        $data = array(
            'name' => $this->name,
            'address' => $this->address,
            'pm_day_of_week' => $this->pm_day_of_week,
            'pm_datetime' => $this->pm_datetime,
        );

        $rules = array(
            'name' => ['required', 'unique:congregations'],
            'address' => ['required'],
            'pm_day_of_week' => ['required', 'integer', 'between:0,6'],
            'pm_datetime' => ['required', 'regex:/([01]?[0-9]|2[0-3]):[0-5]?[0-9]:[0-5][0-9]/'],
        );

        return Validator::make($data, $rules);
    }

    public function getDates()
    {
        return array_merge_recursive(parent::getDates(), array(
            'pm_datetime',
            'cbs_datetime',
        ));
    }
}

이 방법에 대한 자세한 내용은 Laravel 앱의 코드를 구성하는 데 사용됩니다. : https://github.com/rmariuzzo/Pitimi


제 생각에는 라 라벨에 이미 비즈니스를 저장하기 위해 많은 옵션이 있습니다.

짧은 답변 :

  • laravel의 Request객체를 사용 하여 입력을 자동으로 확인한 다음 요청의 데이터를 유지합니다 (모델 생성). 요청 에서 모든 사용자 입력을 직접 사용할 수 있으므로 여기서 수행하는 것이 좋습니다.
  • laravel의 Job객체를 사용하여 개별 구성 요소가 필요한 작업을 수행 한 다음 간단히 디스패치하십시오. Job서비스 클래스를 포함 한다고 생각 합니다. 비즈니스 로직과 같은 작업을 수행합니다.

긴 (더) 대답 :

필요할 때 리포지토리 사용 : 리포지토리는 과도하게 확장 될 수 있으며 대부분의 경우 단순히 accessor모델 로 사용됩니다 . 나는 그들이 확실히 약간의 사용이 있다고 생각하지만, 당신이 laravel을 완전히 버릴 수 있도록 그 정도의 유연성 필요한 방대한 응용 프로그램을 개발하지 않는 한 저장소에서 멀리 떨어져 있습니다. 나중에 자신에게 감사하고 코드는 훨씬 더 간단해질 것입니다.

PHP 프레임 워크를 변경 하거나 laravel이 지원하지 않는 데이터베이스 유형 으로 변경할 가능성이 있는지 자문 해보십시오.

대답이 "아마도 아닐 것"이라면 저장소 패턴을 구현하지 마십시오.

위의 것 외에도 Eloquent와 같은 뛰어난 ORM 위에 패턴을 두드리지 마십시오. 필요하지 않은 복잡성을 추가하는 것 뿐이며 전혀 도움이되지 않습니다.

서비스를 드물게 활용 : 나에게 서비스 클래스는 주어진 종속성으로 특정 작업을 수행하는 비즈니스 로직을 저장하는 장소 일뿐입니다. Laravel은 'Jobs'라고하는 즉시 사용할 수 있으며 맞춤 서비스 클래스보다 훨씬 더 유연합니다.

라 라벨이 MVC논리 문제에 대한 다방면의 해결책을 가지고 있다고 생각 합니다. 그것은 단지 문제 또는 조직입니다.

예:

요청 :

namespace App\Http\Requests;

use App\Post;
use App\Jobs\PostNotifier;
use App\Events\PostWasCreated;
use App\Http\Requests\Request;

class PostRequest extends Request
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'title'       => 'required',
            'description' => 'required'
        ];
    }

    /**
     * Save the post.
     *
     * @param Post $post
     *
     * @return bool
     */
    public function persist(Post $post)
    {
        if (!$post->exists) {
            // If the post doesn't exist, we'll assign the
            // post as created by the current user.
            $post->user_id = auth()->id();
        }

        $post->title = $this->title;
        $post->description = $this->description;

        // Perform other tasks, maybe fire an event, dispatch a job.

        if ($post->save()) {
            // Maybe we'll fire an event here that we can catch somewhere else that
            // needs to know when a post was created.
            event(new PostWasCreated($post));

            // Maybe we'll notify some users of the new post as well.
            dispatch(new PostNotifier($post));

            return true;
        }

        return false;
    }
}

컨트롤러 :

namespace App\Http\Controllers;

use App\Post;
use App\Http\Requests\PostRequest;

class PostController extends Controller
{

   /**
    * Creates a new post.
    *
    * @return string
    */
    public function store(PostRequest $request)
    {
        if ($request->persist(new Post())) {
            flash()->success('Successfully created new post!');
        } else {
            flash()->error('There was an issue creating a post. Please try again.');
        }

        return redirect()->back();
    }

   /**
    * Updates a post.
    *
    * @return string
    */
    public function update(PostRequest $request, $id)
    {
        $post = Post::findOrFail($id);

        if ($request->persist($post)) {
            flash()->success('Successfully updated post!');
        } else {
            flash()->error('There was an issue updating this post. Please try again.');
        }

        return redirect()->back();
    }
}

위의 예에서 요청 입력은 자동으로 유효성이 검사되고 우리가해야 할 일은 persist 메서드를 호출하고 새 Post를 전달하는 것입니다. 나는 가독성과 유지 보수가 항상 복잡하고 불필요한 디자인 패턴보다 우선해야한다고 생각합니다.

그런 다음 게시물이 이미 존재하는지 여부를 확인하고 필요할 때 대체 논리를 수행 할 수 있기 때문에 게시물 업데이트에도 똑같은 지속 방법을 사용할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/23595036/mvc-laravel-where-to-add-logic

반응형