4

->flush() 呼び出しを Symfony2 アプリケーションのどこに配置するかを決めるのに問題があります。私たちに「インスピレーション」を与えることができるかどうか見てみましょう。

私たちのアプリケーションは非常に大きいです。現在、約 30 のバンドルがあります。2 つの別々の開発チームがあります。1 つはフロントエンド (コントローラー + 小枝) を担当し、もう 1 つはコア (データベース + サービス + モデルなど) を担当します。

フロントエンドは 1 つのプロジェクト (独自のバンドルがあり、ドクトリン モデル、ロジック、サービスはありませんが、小枝、パブリック イメージ、CSS、およびコントローラーがあります) であり、1 つのリポジトリに存在します。

Core は別のプロジェクト (サービス、モデル オブジェクトなどを提供する独自のバンドルがあり、内部に doctrine オブジェクトがあり、コントローラーも小枝もありません) であり、別のリポジトリに存在します。

このアプローチの目標は、当社の製品がさまざまなフロントエンド (Web 用のコア + フロントエンド 1、モバイル用のコア + フロントエンド 2、通常のユーザーを管理するための特別な Web を備えたサポートチーム用のコア + フロントエンド 3) で提供されることです。したがって、すべての「ロジック」は「コア内」にあり、いずれかのフロントエンド プロジェクトが同じサービスを使用しているため、コアの改善により、フロントエンドのすべての部分を再テストすることなく、すべてのデプロイが改善されます。

だから...私たちはコントローラがドクトリンオブジェクトに決してアクセスしないようにしようとしていますが、「モデリングレイヤー」にアクセスするようにしています。フロントエンドではなく、コアのみを再テストする必要があります。

DBへのすべてのアクセスが「カプセル化」されるようにモデルを作成しようとしているため、コントローラーは教義にアクセスするのではなく、教義を使用する「サービス」にアクセスします。オブジェクト「cars」と「people」を扱うと仮定すると、コントローラーは「cars_manager」サービスまたは「people_manager」サービスにアクセスして、必要なすべての操作 (オブジェクトの作成、取得など) を実行できます。

フラッシュコールをどこに置きますか?

例(読みやすくするために疑似コードで):

controller AjaxJsonAddDriverToCar( $CarId, $DriverId )
{
    try
    {
        $Cars = getService( "core.cars_manager" );
        $Car = $Cars->getCarById( $CarId );
        $Car->addDriver( $DriverId );
        $Result = JSON_OK;
    }
    catch
    {
        $Result = JSON_FAIL;
    }

    return $Result;
}

コントローラーがコアがどのように実装されているかを認識していない場合、ドクトリンを取得して ->flush() を実行するべきではありません。

インスピレーションは大歓迎です。ありがとう。

4

2 に答える 2

3

コントローラーからのフラッシュの呼び出しを避けるために、特定のコントローラー アクションのデータベースを更新するすべてのコードを、最後に flush() を呼び出すサービス メソッドにカプセル化することをお勧めします。メソッドは例外をスローします。

あなたが与えた例では、これは次のように置き換えることで実現できます。

    $Cars = getService( "core.cars_manager" );
    $Car = $Cars->getCarById( $CarId );
    $Car->addDriver( $DriverId );
    $Result = JSON_OK;

と:

    $Cars = getService( "core.cars_manager" );
    $Cars->addDriverToCar($CarId, $DriverId);
    $Result = JSON_OK;

CarsManager::addDriverToCar は次のようになります。

    $Car = $this->getCarById( $CarId );
    $Car->addDriver( $DriverId );
    $this->getEntityManager()->flush();

ただし、これは単一のエンティティのみを更新するため、かなり単純化された例であり、フラッシュの利点は、作業単位の完了を構成する、追加/削除/更新したすべてのエンティティへの変更を保存することです。

あなたが説明したアプローチは、エンティティ固有のマネージャーに言及しています。複雑なエンティティのマネージャが、さまざまなタイプの複数のエンティティを作成/更新/削除するメソッドを持つことができない理由はありませんが、マネージャ クラスの責任を考慮する価値があります。エンティティの単純な検索および CRUD タイプの操作を処理するエンティティ タイプごとにマネージャを用意し、エンティティ マネージャと特定の機能または機能セットの処理を処理するコントローラとの間に追加のマネージャ レイヤーを用意すると便利な場合があります。

于 2012-06-13T12:01:41.707 に答える
2

私が最初に考えたのは、車に自分自身を保存するように指示する、ある種のアクティブ レコードでした。Car はボイラープレート コードにすぎないため、データベースの実装を認識し、いくつかのサービスにアクセスすることは問題ありません。

私の 2 番目の考えは、車の管理者は節約について知っておくべきだということでした。つまり、それはエンティティ管理者と非常に似たものになり、あなたは彼にフラッシュを伝え、彼はフラッシュします。基本的にエンティティマネージャを抽象化し、少し使いやすくします (直接使用するリポジトリがないため)。

私の3番目の考えはwtfでした。フロントエンドとバックエンドを分離したいということは理解しています。フロントエンドがモデルを操作できないのに定型コードを操作する必要がある理由がわかりません。面白いことに、モデルが変更されると、その間のレイヤーも変更されます。レイヤーを変更したくない場合は、モデルを変更することもできません (どちらでも同じです)。たとえば、データベースからフィールドを削除したい場合: 注釈を削除して無視します。大丈夫です。名前を変更すると、いつでも古いゲッターとセッターを配置して、新しい名前で操作できます。等々。

もちろん、全体像はわかりませんが、もう一度よく考えてみてください ;)

そして、ここで別の考えがあります: たぶん、全体が成功したか失敗したかを抽象化レイヤーに伝えたいと思うかもしれません。彼は、実行する必要があるすべてのことを行います (データベースのフラッシュ、ログの書き込み、電子メールの送信など)。ユースケースを成功と失敗に絞り込むことができ、サービスが何をすべきかを知っている場合、これが最も簡単な解決策かもしれません。

于 2012-06-13T10:46:22.850 に答える