2016-08-23 2 views
11

나는 자신의 저장소, 관리자, 제공자 등으로 여러 사용자 유형을 정의 할 수있는 사용자 정의 사용자 번들을 만들고 있습니다. 따라서 한정된 컨트롤러 세트를 생성하는 대신 컨트롤러 팩토리는 정의 된 사용자 유형 및 구성을 기반으로 컨트롤러를 생성합니다. 그러나 이것은 중요한 질문을 제기합니다 - 공장은 어디에서 어떻게 운영되어야합니까?symfony : 컨트롤러 팩토리

이제 공장에서 컨트롤러를 만드는 것만으로는 충분하지 않으며, 어딘가에 모든 경로를 설정해야한다는 것을 기억하십시오.

질문은 -이 아키텍처에 가장 적합한 것은 무엇입니까? 확장의 load 방법

  1. 로드 공장의 정의를하고, 거기에 모든 컨트롤러를 만드는 :

    그것이 내가 내 코드를 삽입하는 레이어를 선택에 관해서

    , 나는 다른 사람의 사이에서, 고려했다. 문제 : 라우터가 컨테이너를 만들기 전에 발생하기 때문에 라우터를 사용할 수 없으므로 같은 위치에 경로를 만들 수 없습니다.

  2. Sooo ... 아마도 컴파일러가 통과 했습니까? 하지만 컴파일러 패스는 구성에 액세스 할 수 없습니다 ... 내 말은 ... 실제로 구성을로드하고 수동으로 처리하는 경우 사실이지만 여전히 좋은 장소인지는 확실하지 않지만 지금이 솔루션을 향해 기울고 있습니다. 생성 경로에

온다 :

  1. 내가 컨트롤러 공장에서 경로 생성 로직을 배치해야 하는가? 하지만 컨트롤러를 서비스로 만들고 공장에서 만든 컨트롤러의 serviceId에 액세스 할 수 없으며 route를 만드는 데 serviceId가 필요합니다.

  2. 컨트롤러 자체에 있습니까? 즉, 주석 경로가 작동하는 방식이므로 실행 가능할 수 있습니다. 컨트롤러는 내 자신의 ControllerInterface과 같은 메소드를 getRoutes으로 구현해야하고, 외부 서비스/컴파일러 패스는 먼저 컨트롤러로 서비스를 생성 한 다음 해당 컨트롤러에서 경로를 가져와 수정해야합니다. 컨트롤러의 serviceId를 추가하고 라우터에 추가하십시오.

  3. 다른 옵션이 있습니까?

컨트롤러의 공장 패턴과 관련된 정보가 상당히 부족합니다. :).

+0

당신이 요청별로 할 필요가이 뭔가? 아니면 명령을 통해 한 번 수행 할 수있는 무언가입니까? – Cerad

+0

무엇을 참고 하시겠습니까? 컨트롤러를 만드는 이벤트에 대해 질문하는 경우 컨테이너와 경로를 만들 때 한 번만 수행해야합니다. 컨트롤러 (서비스로서)와 루트는 Symfony에 의해 평소처럼 캐싱되어야합니다. –

+0

죄송합니다. "컨트롤러 ** 정의 **를 만드는 이벤트에 대해 질문하는 경우"를 의미합니다. –

답변

5

The first version of API Platform도 유사한 기술을 사용했다.

첫 번째 단계는 경로를 등록하는 것입니다. 경로는 _controller 경로 속성 아래에 정의 된 컨트롤러와 URL 패턴을 매핑합니다. 라우팅 구성 요소와 HttpKernel 구성 요소가 서로 연결되는 방식입니다 (두 구성 요소간에 강력한 결합이 없음). 경로는 RouteLoader을 생성하여 등록 할 수 있습니다. http://symfony.com/doc/current/routing/custom_route_loader.html

예를 들어 API Platform, Sonata 및 Easy Admin의 작동 방식은 다음과 같습니다.

런타임시 _controller 속성 아래에 지정된 호출 가능 프로그램이 실행됩니다. 매개 변수로 HTTP 요청을 수신하고 HTTP 응답을 반환해야합니다. 필요한 경우 다른 서비스 (심지어 컨테이너까지)에 액세스 할 수 있습니다.

컨트롤러는 모든 호출 가능 (메서드, 함수, 호출 가능 클래스 ...) 될 수 있지만 다음 구문 my_controller_service:myAction (http://symfony.com/doc/current/controller/service.html 참조) 덕분에 서비스가 될 수도 있습니다.

DependencyInjection 구성 요소를 사용하면 팩토리를 사용하여 서비스를 빌드 할 수 있습니다 (http://symfony.com/doc/current/service_container/factories.html). 팩토리 메소드는 다른 서비스 또는 매개 변수 (config)를 수신 할 수 있습니다.

요약하면 : 당신이 당신의 컨트롤러를 작성해야하는 경우 물론

# app/config/services.yml 
services: 
    # ... 

    app.controller_factory: 
     class: AppBundle\Controller\ControllerFactory 
     arguments: ['@some_service', '%some_parameter%] 

    app.my_controller: 
     class:  AppBundle\Controller\ControllerInterface 
     factory: 'app.controller_factory:createController' 
     arguments: ['@some_service', '%some_parameter%] 

:

1/다음과 같이, 그것을 만들기 위해 공장을 사용하여 컨트롤러에 대한 서비스 정의를 등록 정의는 프로그래밍 방식으로 AppBundle\DependencyInjection\AppBundleExtension 클래스에 있습니다. 코드 중복을 피하기 위해 abstract 서비스 정의를 사용할 수도 있습니다 (http://symfony.com/doc/current/service_container/parent_services.html).

2/RouteLoader 인스턴스를 등록하여 Route 인스턴스를 등록하십시오. 그런 다음 https://github.com/api-platform/core/blob/1.x/Routing/ApiLoader.php

서비스로이 경로 로더를 등록 :이 예에 좀 걸릴 수 있습니다

# app/config/services.yml 
services: 
    app.routing_loader: 
     class: AppBundle\Routing\MyLoader 
     arguments: ['@some_service', '%some_parameter%] 
     tags: 
      - { name: routing.loader } 

3 /이 RouteLoader 실행하는 라우터를주기 :

# app/config/routing.yml 
app: 
    resource: . # Omitted 
    type: mytype # Should match the one defined in your loader's supports() method 

모두 완료를 !

(나는 심포니 코어 팀 구성원뿐만 아니라 API 플랫폼의 창조자, 그래서 이것이 자기 의견을 고집 답변입니다.)

+0

그래서 일부 구성을 기반으로 컨트롤러를 만들고 싶다면이 구성을 라우트 로더에 전달해야합니까? 처음에는이 방법이 마음에 들지 않았습니다. 왜냐하면 어떻게 든 같은 위치에 라우트와 컨트롤러를 만들 수 있다고 생각했기 때문입니다. (서로가 없으면 쓸모가 없기 때문입니다.)하지만 너무 깊이 생각할 수도 있습니다. 이 상세한 설명에 감사드립니다 :). –

+0

요청 (컨트롤러) 라우팅 및 처리는 분리되어야하는 두 가지 작업입니다. 정말로 하나의 클래스 만 만들고 싶다면 컨트롤러 팩토리는 또한'LoaderInterface'를 구현할 수 있습니다. 그것은 작동해야하지만, 그것은 고체 원칙을 어기는. –

0

사용자 액세스 제어를 확인하기 위해 setContainer 메소드를 사용할 수 있습니다. MySolution :

class AuthBaseController extends Controller{ 
    /** 
    * @var \stdClass 
    */ 
    protected $user = null; 

    /** 
    * this is a function for any role. For example, edit posts 
    * @var int 
    */ 
    protected $functionId=null; 

    // this is initilizer function for all controllers. If any controller access to this controller then set $systemAccess to true 
    public function setContainer(ContainerInterface $container = null, $systemAccess= false) { 
     parent::setContainer($container); 
     if($systemAccess) return; 
     $session = $this->get("session"); 
     if($session->has('YOUR_USER_KEY')){ 
      $this->user = json_decode($session->get('YOUR_USER_KEY')); 
      if(!in_array($this->functionId,$this->user->userFunctions) && !is_null($this->functionId)){ 
       // if user havn't access to this controller 
       throw new AccessDeniedException("You can not access to this page!"); 
      } 
     }else{ 
      header("Location:".$this->generateUrl("user_login")); 
     } 
    } 
} 

class TaskManagementController extends AuthBaseController { 
    /** 
    * @var int 
    */ 
    protected $functionId=24; 

    public function indexAction(Request $request){ 
     //your action codes 
     } 
} 
2

이 공장은, 먼저 컴파일 패스에서 사용자 지정 경로 로더를 사용하여 경로를 만들 수있는 몇 가지 규칙을 정의 할 필요가 작동하려면, 나는 당신이 또한 라우팅 매칭과 해상도를 정의해야한다 생각 프로 시저를 사용하여 수신 된 경로를 확인한 다음 공장에서 생성 한 구체적인 라우터와 라우트 패턴 또는 값 사이의 관계를 정의하고 마지막으로 콘크리트 라우터 내의 기능에 요청을 전달하는 규칙을 정의합니다.

본인은 여러 번 질문을 읽었으나이 접근법의 장점은 여전히 ​​없습니다.상속 또는 구성으로 라우터를 만들 계획입니까? 콘크리트를 정의하는 룰셋 (매개 변수를 포함하고 완전히 "구체적"이 아니더라도) 경로는 기능 수준까지 올라야하며 좋은 명명 규칙에 의해 해결 될 수 있다고하더라도 여전히 많은 어려움을 겪고 있습니다.

물론 의견입니다.