2016-08-23 8 views
11

私は、独自のリポジトリ、マネージャ、プロバイダなどを使って複数のユーザタイプを定義できるようにカスタムのユーザバンドルを作成しています。そのため、限られたコントローラセットを作成する代わりに、定義されたユーザタイプと設定に基づいてコントローラを生成するコントローラファクトリ。しかし、これは重要な疑問を提起します - その工場はどこでどのように動作するべきですか?symfony:コントローラの工場

ここでは、工場でコントローラを作成するだけでは十分ではないことにご注意ください。また、すべてのルートをどこかに設定する必要があります。

質問は - これにはどのようなアーキテクチャが最適でしょうか?拡張のload方法で

  1. ロード工場の定義を、そしてそこにすべてのコントローラを作成:

    それは私が私のコードを配置しますレイヤーを選択することになると、私は他の人の間で、検討していました。問題:コンテナビルド前にルータが使用できないため、ルータは同じ場所にルートを作成できませんでした。

  2. Sooo ...おそらくコンパイラのパスですか?しかし、コンパイラパスはコンフィギュレーションへのアクセス権を持っていません...つまり、実際にはコンフィギュレーションをロードして手動で処理すれば良いですが、これが良いかどうかまだ分かりませんが、今このソリューションに向かっている。

それがルートを作成することになる:

  1. 私は、コントローラの工場でルート作成ロジックを置くべきか?しかし、私はサービスとしてコントローラを作成しており、工場は作成されたコントローラのserviceIdにアクセスすることができず、serviceIdはルートを作成するために必要です。

  2. コントローラ自体には?つまり、注釈ルートがどのように機能するのか、それは実行可能な可能性があります。コントローラは私自身のControllerInterfaceのようなものを実装しなければならないでしょう。方法はgetRoutesで、外部サービス/コンパイラのパスはまずコントローラとしてサービスを作成してから、上記のコントローラからルートを取得して変更する必要があります。コントローラのserviceIdを追加してルータに追加してください...これはどうやら乱雑に見えます。

  3. その他のオプションはありますか?

コントローラーのこの特定のパターンに関する情報がかなり不足しています。

+0

はあなたが要求ごとに行う必要があり、この何かか?それともコマンドで一度やり遂げることができるものなのでしょうか? – Cerad

+0

あなたは何を参照していますか?コントローラーを作成するイベントについて質問する場合は、コンテナとルートを構築するときに一度だけ実行する必要があります。コントローラ(サービスとして)とルートは通常のようにSymfonyによってキャッシュされるべきです。 –

+0

申し訳ありませんが、私は "コントローラの**定義**を作成した事例について聞いたら"を意味しました。 –

答えて

5

The first version of API Platformも同様の手法を用いていました。

最初の手順はルートを登録することです。ルートは、_controllerルート属性の下に定義されたコントローラを使用してURLパターンをマッピングします。 RoutingコンポーネントとHttpKernelコンポーネントがどのようにリンクされているか(これらの2つのコンポーネント間の強い結合はありません)。 RouteLoaderを作成して経路を登録することができます。http://symfony.com/doc/current/routing/custom_route_loader.html

APIプラットフォーム、Sonata、およびEasy Adminの仕組みを示しています。

実行時に、_controller属性で指定された呼び出し可能ファイルが実行されます。それはパラメータでHTTPリクエストを受け取り、HTTPレスポンスを返します。必要に応じて、他のサービス(さらにはコンテナ)にアクセスすることができます。

コントローラは任意の呼び出し可能(メソッド、関数、呼び出し可能なクラスなど)でもかまいませんが、次の構文my_controller_service:myAction(を参照)のおかげでサービスになることもできます。

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 

すべてを行います!

(私はsymfonyのコアチームメンバーだけでなく、APIプラットフォームの作成者ですので、これは独断的な答えである。)

+0

何らかの設定に基づいてコントローラを作成したい場合、この設定をルートローダーに渡す必要がありますか?最初はこのアプローチが嫌いでした。なぜなら、何とか同じ場所にルートとコントローラを作成するにはどうしたらいいのですが(私はお互いに無駄ですから)、これについて深く考えているかもしれません。この詳細な説明をありがとう:) –

+0

リクエスト(コントローラ)のルーティングと処理は、デカップリングする必要のある2つの異なる操作です。クラスを1つだけ作成したい場合は、コントローラファクトリでも '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

が工場は、まずあなたがコンパイルパスでカスタムルートローダーを使用してルートを作成するためのいくつかのルールを定義する必要があることを動作させるために、私はあなたにも、ルーティングのマッチングと解像度をカスタマイズする必要がある必要がありますねそのルートパターンまたは値とファクトリによって作成された具体的なルータとの間の関係を定義し、最後に具体的なルータ内のファンクションにその要求を渡すルールを含む。

私はあなたの質問を何度も読んでいますが、私はまだこのアプローチの利点を見ていません。継承や合成によってルータを作成しようとしていますか?コンクリートを定義するためのルールセット(パラメータが含まれていても完全に「具体的」でない場合でも)は、機能レベルまで移行する必要がありますが、これは良い命名規則で解決することができますが、まだ多くの困難があります。

もちろん、意見です。

関連する問題