6

承認されていない/ドラフトエンティティをフィルタリングする手段として機能するDoctrine2リスナーとフィルターがあります。これは、適用されているエンティティで正常に機能しますが、関係に対して機能させる方法がわかりません。

エンティティがカテゴリと呼ばれているとしましょう。次に、そのカテゴリに関連するfindBy()製品があり、製品に対して実行するときに、関連するカテゴリが承認されていることを確認するクエリが必要です。

select * from products p
left join category c on p.category_id = c.id
where p.id = 5 and c.approved = true

太字のビットは、フィルターまたは同等のものによって注入する必要があるものです。

これを実装するにはどうすればよいですか?

これまでのところ、フィルターの where の一部としてサブクエリが挿入されていますが、これは地獄のようで、もっと良い方法があるに違いないと考えています。

class ApprovableFilter extends SQLFilter
{
    protected $listener;
    protected $entityManager;

    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
    {
        $config = $this->getListener()->getConfiguration($this->getEntityManager(), $targetEntity->name);

        /* this bit works fine for the category */

        if (isset($config['approvable']) && $config['approvable']) {
            $column = $targetEntity->columnNames[$config['fieldName']];

            return $targetTableAlias.'.'.$column.' = true';
        }

        /* this bit works for products.. but seems like a pretty poor solution */

        if (isset($targetEntity->associationMappings['category'])) {
            $config = $this->getListener()->getConfiguration(
                $this->getEntityManager(),
                $targetEntity->associationMappings['category']['targetEntity']
            );

            return '(
                select d.id from dealership d
                where d.id = '.$targetTableAlias.'.dealership_id
                and d.'.$config['fieldName'].' = true
            ) is not null';
        }
    }
4

2 に答える 2

2

注釈を使用すると、ソリューションをもう少し一般的にすることができます。私はそれについて要旨を書いています: https://gist.github.com/technetium/0c62164400a411e9ffc3713260448b25

于 2016-04-14T07:51:34.653 に答える
1

私が考えることができる最善の方法は、Category オブジェクトを介して製品を取得することです。
そうすれば、category.approved フィールドのみをフィルタリングする必要があります。

例えば:

public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
    $config = $this->getListener()->getConfiguration($this->getEntityManager(), $targetEntity->name);

    /* this bit works fine for the category */

    if (isset($config['approvable']) && $config['approvable']) {
        $column = $targetEntity->columnNames[$config['fieldName']];

        return $targetTableAlias.'.'.$column.' = true';
    }
}

次に、Category エンティティに製品コレクションが必要です (Bidirectional リレーションがあると仮定します)。

use Doctrine\Common\Collections\ArrayCollection;

class Category {
    /**
     * @var ArrayCollection $products
     * @ORM\OneToMany(targetEntity="Product", mappedBy="category")
     */
    private $products;

    public function __construct()
    {
        $this->products = new ArrayCollection;
    }

    public function getProducts()
    {
        return $this->products;
    }
}

そうすれば、最初にカテゴリを取得できます

$category = $this->get('doctrine')->getRepository('SomeBundle:Category')->find(5);
if( $category ) {
    //Here you now the category is approved
    $products = $category->getProducts();
}

お役に立てれば。

編集:

@lracicot の質問に答え、一方向の関係の例を示すには、次のように ProjectRepository メソッドを作成します。

...
findByCategoryApproved( $product_id, $approved = true )
{
    $query =
        'SELECT p
         FROM AcmeBundle:Product
         LEFT JOIN p.categories c
         WHERE p.id = :id AND c.approved = :approved';
    
    return $this
        ->getEntityManager()
        ->createQuery( $query )
        ->setParameter( 'id', $product_id )
        ->setParameter( 'approved', $approved )
        ->getOneOrNullResult();
}

...

$product = $doctrine
     ->getRepository('AcmeBundle:Product')
     ->findByCategoryApproved(5);
于 2013-01-14T20:28:07.040 に答える