4

現在のユーザーの資格情報に基づいてクエリを変更できるように、何らかのウォーカーを介してすべての教義クエリを実行することは可能ですか? 理想的には、すべてのクエリでカスタム ウォーカーの setHint を明示的に呼び出す必要はありません。現在の SecurityContext をウォーカーに渡す機能が制限されるからです。

また、フィルターを使用して結合条件を変更することはできないため、Doctrine フィルターを使用しないことをお勧めします。また、「IN」句を使用する必要があり、パフォーマンスに深刻な影響を与える可能性があります。

現在、ユーザーの資格情報に基づいて QueryBuilder を変更するサービスを使用していますが、新しい QueryBuilder を作成するたびにサービスを呼び出す必要があるため、面倒です。 (クエリを変更する必要があるすべてのリポジトリにサービスを挿入する必要があるためです。

うまくいけば、私はこれを十分に明確に説明しました。フィードバックをお待ちしております。

4

2 に答える 2

1

カスタム AST Walkerを作成し、 defaultQueryHint(Doctrine 2.5 の新機能) 構成オプションを使用して、すべてのクエリでこの walker を使用するようにアプリケーションをセットアップできます。

<?php
/** @var \Doctrine\ORM\EntityManager $em */
$em->getConfiguration()->setDefaultQueryHint(
    Query::HINT_CUSTOM_TREE_WALKERS,
    ['YourWalkerFQClassName']
)
于 2015-05-04T09:50:37.663 に答える
1

私は自分の問題を解決したと思います。他の誰かがこれらの結果を達成するためのよりエレガントな方法を持っている場合は、遠慮なく説明してください。すべてのクエリを変更するために、カスタム EntityManager とカスタム EntityRepository を作成しました。

カスタム EntityManager で、2 つのメソッドを上書きしました。create() および getRepository()

public static function create($conn, Configuration $config, EventManager $eventManager = null)
{
    if ( ! $config->getMetadataDriverImpl()) {
        throw ORMException::missingMappingDriverImpl();
    }

    switch (true) {
        case (is_array($conn)):
            $conn = \Doctrine\DBAL\DriverManager::getConnection(
                $conn, $config, ($eventManager ?: new EventManager())
            );
            break;

        case ($conn instanceof Connection):
            if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
                 throw ORMException::mismatchedEventManager();
            }
            break;

        default:
            throw new \InvalidArgumentException("Invalid argument: " . $conn);
    }

    return new MyCustomEntityManager($conn, $config, $conn->getEventManager());
}

このメソッドで唯一変更されているのは、独自の EntityManger( MyCustomEntityManager ) を返すことです。次に、次のように getRepository メソッドをオーバーレイしました。

public function getRepository($entityName)
{
    $entityName = ltrim($entityName, '\\');

    if (isset($this->repositories[$entityName])) {
        return $this->repositories[$entityName];
    }

    $metadata = $this->getClassMetadata($entityName);
    $repositoryClassName = $metadata->customRepositoryClassName;

    if ($repositoryClassName === null) {
        $repositoryClassName = "Acme\DemoBundle\Doctrine\ORM\MyCustomEntityRepository";
    }

    $repository = new $repositoryClassName($this, $metadata);

    $this->repositories[$entityName] = $repository;

    return $repository;
}

ここでも、1 行だけ変更しました。DBAL 構成に依存してデフォルトの $repositoryClassName を取得する代わりに、独自のデフォルト リポジトリAcme\DemoBundle\Doctrine\ORM\MyCustomEntityRepositoryを指定しました。

独自のカスタム EntityRepository を作成したら、あとは無限です。次のように、サービスをリポジトリに注入するか (現在、JMS Di アノテーションを使用しています。以下で説明します)、createQueryBuilder メソッドで QueryBuilder に対してカスタム アクションを実行できます。

use JMS\DiExtraBundle\Annotation as DI;

class MyCustomEntityRepository extends EntityRepository
{
    private $myService;

    public function createQueryBuilder($alias)
    {
         $queryBuilder = parent::createQueryBuilder($alias);

          /** INSERT CUSTOM CODE HERE **/

          return $queryBuilder;
    }

    /**
    * @DI\InjectParams({
    *     "myService" = @DI\Inject("my_service_id")
    * })
    */
    public function setMyService(MyServiceInterface $myService)
    {
        $this->myService = $myService;
    }
}

独自の EntityRepository を作成したら、このカスタム機能を必要とするすべてのリポジトリで MyCustomEntityRepository を拡張する必要があります。さらに一歩進んで独自の QueryBuilder を作成し、これをさらに拡張することもできます。

于 2012-11-28T15:49:33.190 に答える