steevanb/doctrine-entity-merger

添加提示 MERGE_ENTITY 以合并由多次查询检索的字段

1.0.5 2018-05-24 10:15 UTC

This package is auto-updated.

Last update: 2024-08-28 11:29:48 UTC


README

version doctrine php Lines Total Downloads SensionLabsInsight Scrutinizer

doctrine-entity-merger

当你在DQL中使用PARTIAL时,你只会检索需要的字段,而不是所有实体字段。

但是,如果你在同一个实体上执行了2次PARTIAL,但字段不同,你将遇到这个问题

class FooEntity
{
    protected $id;
    protected $name;
    protected $description;
}

$foo1 = $repository
    ->createQueryBuilder('foo')
    ->select('PARTIAL foo.{id, name}')
    ->where('site.id = 1')
    ->getQuery()
    ->getSingleResult();

var_dump($foo1->getDescription()); // null, that's fine, description is not in PARTIAL

$foo2 = $repository
    ->createQueryBuilder('foo')
    ->select('PARTIAL foo.{id, name, description}')
    ->where('site.id = 1')
    ->getQuery()
    ->getSingleResult();

// $foo1 is same object as $foo2, cause Doctrine know first query hydrated $foo1
// so, when you ask same entity (same id in query) with 2nd query, Doctrine will execute SQL,
// but will not hydrate a new entity
// UnitOfWork will return instance of Foo who is already hydrated, with first query
var_dump(spl_object_hash($foo1) === spl_object_hash($foo2)); // true

// but, as Doctrine return $foo1 in 2nd query, your new field description will not be defined in $foo1
var_dump($foo1->getDescription()); // null, but we want it, cause it's defined in PARTIAL 2nd query

你可以使用 steevanb\DoctrineEntityMerger\QueryHint::MERGE_ENTITY 来定义 $foo1 中的描述

use steevanb\DoctrineEntityMerger\QueryHint;

$foo1 = $repository
    ->createQueryBuilder('foo')
    ->select('PARTIAL foo.{id, name}')
    ->where('site.id = 1')
    ->getQuery()
    ->getSingleResult();

var_dump($foo1->getName()); // 'My name' for example
var_dump($foo1->getDescription()); // null, that's fine, description is not in PARTIAL

$foo1->setName('New name');
var_dump($foo1->getName()); // 'New name'

$foo2 = $repository
    ->createQueryBuilder('foo')
    ->select('PARTIAL foo.{id, description}')
    ->where('site.id = 1')
    ->getQuery()
    ->setHint(QueryHint::MERGE_ENTITY, true)
    ->getSingleResult();

var_dump($foo1->getName()); // 'New name', MERGE_ENTITY will not change Foo::$name value if it was already defined in another query before

var_dump($foo1->getDescription()); // 'My description'

变更日志

安装

由于 doctrine-entity-merger 使用 steevanb/doctrine-events,请查看如何安装它(在此处添加了composer依赖项,你不需要为steevanb/doctrine-events添加它)

steevanb/doctrine-events

将其添加到你的composer.json中

{
    "require": {
        "steevanb/doctrine-entity-merger": "^1.0.5",
    }
}

添加EntityMergerSubscriber

$entityManager->getEventManager()->addEventSubscriber(
    new steevanb\DoctrineEntityMerger\EventSubscriber\EntityMergerSubscriber()
);

如果你想将MERGE_ENTITY提示添加到所有查询中,你可以这样做

$entityManager->getConfiguration()->setDefaultQueryHint(
    steevanb\DoctrineEntityMerger\QueryHint\QueryHint::MERGE_ENTITY,
    true
);

例如,如果你在一个Symfony项目中,你可以在AppKernel中添加它

# app/AppKernel.php

use Doctrine\ORM\EntityManagerInterface;
use steevanb\DoctrineEntityMerger\QueryHint;
use steevanb\DoctrineEntityMerger\EventSubscriber\EntityMergerSubscriber;

class AppKernel
{
    public function boot()
    {
        parent::boot();
        
        foreach ($this->getContainer()->get('doctrine')->getManagers() as $manager) {
            if ($manager instanceof EntityManagerInterface) {
                // add hint MERGE_ENTITY to all your queries
                $manager->getConfiguration()->setDefaultQueryHint(QueryHint::MERGE_ENTITY, true);

                // add listener, who use steevanb/doctrine-events to change UnitOfWork::createEntity()
                // to take into account MERGE_ENTITY hint
                $manager->getEventManager()->addEventSubscriber(new EntityMergerSubscriber());
            }
        }
    }
}