質問

Zend Frameworkを使用してPHPを使用し、Doctrine2をORMとして使用するアプリケーションがあります。私の質問は、コントローラーが基礎となるモデルと永続性層について知っておくべきことに関連しています。理想的には、これは自分自身が「何もない」と言うでしょう - コントローラーは、エンティティがどのように/いつ持続するかについて何も知らないはずです。しかし、これは必ずしも最良の解決策ではないと感じています(?)。

私は「懸念の分離」設計ガイドラインに従おうとしました。私は、モデルでCRUD操作を実行するサービスレイヤーを作成することでこれを行いました。次の例を参照してください。

public function testbuildAction()
{        
    // create section
    $sectionService = new \MyAPP\Model\Service\Acl\SectionService();        
    $sectionA       = $sectionService->createSection('SectionA-NAME');

    // create privilege with the above section
    $privilegeService   = new \MyAPP\Model\Service\Acl\PrivilegeService();
    $privilegeA = $privilegeService->createPrivilege(
                            $sectionA, 
                            \MyAPPFrameWork\Model\Acl\Privilege::PERMISSION_EDIT
                        );

    // create a role with the privilege above. A role must have at least one priv.
    $roleService = new \MyAPP\Model\Service\Acl\RoleService();
    $role        = $roleService->createRole('Role-NAME', $privilegeA); 

    // this loads a managed User object (managed by EntityManager)
    $user = $this->_helper->IdentityLoader(); 
    $user->addRole($role); // add the role to this user
    $userService = new \MyAPP\Model\Service\Core\UserService();        
    $userService->updateUser($user); // persist the updates.
}

ご覧のとおり、コントローラーは永続性について何も知りませんが、この結果を得るには、サービスレイヤーのcreatexxx()またはupdatexxx()メソッドへのすべての呼び出し内でwaste()とflush()の両方を実行する必要があります。私はむしろこのようなことをしたいです:

public function testbuildAction()
{        
    // create section
    $sectionService = new \MyAPP\Model\Service\Acl\SectionService();        
    $sectionA       = $sectionService->createSection('SectionA-NAME');

    // create privilege with the above section
    $privilegeService   = new \MyAPP\Model\Service\Acl\PrivilegeService();
    $privilegeA = $privilegeService->createPrivilege(
                            $sectionA, 
                            \MyAPPFrameWork\Model\Acl\Privilege::PERMISSION_EDIT
                        );

    // create a role with the privilege above. A role must have at least one priv.
    $roleService = new \MyAPP\Model\Service\Acl\RoleService();
    $role        = $roleService->createRole('Role-NAME', $privilegeA); 

    // this loads a managed User object (managed by EntityManager)
    $user = $this->_helper->IdentityLoader(); 
    $user->addRole($role); // add the role to this user

    // persist it all (all service-classes access the same entitymanager).
    $roleService->flush(); // everything is persisted
}

しかし、これにより、Doctrine2が間違った順序でデータベースにオブジェクトを持続するため、Doctrine2が失敗します。特権は、セクションの前に持続します(Dunnoは、Doctrineにこれを順序付けられた方法で実行するよう指示できれば??)。特権は、まだ持続していないセクションで間違ったIDを取得します。

とにかく、ここでの大きな問題は、すべてのオブジェクトが作成され、関係が設定されるまで、フラッシングを延期しようとする必要があるかどうかです。目標は、すべてがデータベースに書き込む1つのトランザクションを持つことです。その結果、コントローラーによってトリガーされる必要があります(オブジェクトと関係の構築がいつ行われるかを知っている唯一のものであるため)。永続レイヤー?

役に立ちましたか?

解決

アントニーは、EntityManagerの__Destruct()に接続するようなものを提案します。ただし、レアリーが変更されたエンティティが変更されたかどうかわからないため、読み取り専用シナリオしか持っていなくても、毎回フラッシュを呼び出したくありません。

したがって、サービスレイヤーはフラッシュするべきではありませんが、コントローラーは、Doctrine EventManagerを簡単に使用して、各サービスレイヤーアクションにイベントを「ReackFlush」で発送させることができます。

$em->getEventManager()->dispatchEvent("requireFlush", new OnFlushEventArgs($em));

おそらく、これのために何らかの利便性機能を書くべきです。

その後、あなたはあなた自身のイベントリスナーを書きます:

class DelayFlushListener
{
    private $requiresFlush = true;
    private $delayFlush = true;

    public function __construct($delayFlush = true) {
       $this->delayFlush = $delayFlush;
    }

    public function requireFlush(EventArgs $args) {
        $this->em = $args->getEntityManager();
        if ($this->delayFlush) {
            $this->requiresFlush = true;
        } else {
            $this->em->flush();
        }
    }

    public function flush() {
         if ($this->requiresFlush) {
             $this->em->flush();
         }
    }
}

今、あなたのブートストラップにそのリスナーを登録してください:

 $listener = new DelayFlushListener();
 $em->getEventManager()->addEventListener(array("requireFlush"), $listener);

また、コントローラー内では、必要に応じて、必要に応じて、必要に応じて、すべてのリクエストでポストディスパッチコールバックでフラッシュをトリガーできます。

 $listener->flush();

他のヒント

私はZend、Php、またはDoctrine2について絶対に何も知らないことをすぐに認めます2 ...

しかし、これはあなたがの実装が必要なように聞こえます 仕事の単位 パターン。私はASP.NETとC#を使用してMVCを使用して作業し、それを行うものを持っています。

私のコントローラーがサービスレイヤーを呼び出しているだけで、トランザクションがPersistenceストアにコミットしているときに制御するのはサービスレイヤー次第です(私の場合はデータベース)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top