vrok / ref-helper
支持与 Doctrine2 实体进行多态关联的实用工具
Requires
- php: >=7.2
- doctrine/doctrine-orm-module: ^1.1.5
- zendframework/zend-servicemanager: ^3.3.2
Requires (Dev)
- phpunit/phpunit: ^6.3.1
- zendframework/zend-coding-standard: ~1.0.0
This package is auto-updated.
Last update: 2024-09-14 23:59:23 UTC
README
支持在 Zend Framework 3 中与 Doctrine 2 进行多态关联的库。
许多应用程序具有多态关系,我们不知道(也不希望在事先知道)哪些实体可以分配给哪些(例如,哪个实体属于哪个)。例如,银行账户可能属于用户或组织,验证可能属于银行账户或用户。
为了支持这种松散耦合,我们将引用实体的类和形成主键的标识符(例如,自增键或复合键)分别存储在引用实体中。引用实体应保持简单 POPO,它们需要实现 Vrok\References\Entity\HasReferenceInterface
,它由 Vrok\References\Entity\HasReferenceTrait
实现,以便重用。接口和特质支持一个实体上的多个引用,例如,引用创建者和所有者。
Vrok\References\Service\ReferenceHelper
通过提供设置和检索引用实体的函数来在此基础上构建。辅助工具还具有限制引用仅限于一个或某些目标类的功能。
使用方法
实体准备
- 在应存储对另一个对象引用的实体上实现
HasReferenceInterface
,使用HasReferenceTrait
以简化操作 - 通过定义每个引用的
$references
属性和${refName}Class
、${refName}Identifiers
属性,将一个或多个引用添加到实体中
use Doctrine\ORM\Mapping as ORM; use Vrok\References\Entity\HasReferenceInterface; use Vrok\References\Entity\HasReferenceTrait; /** * @ORM\Entity() * @ORM\Table(name="sources") */ class Source implements HasReferenceInterface { use HasReferenceTrait; /** * @var array ['refName' => (bool)required, ...] */ protected $references = [ 'nullable' => false, 'required' => true, ]; /** * @var string * @ORM\Column(type="string", length=255, nullable=false) */ protected $requiredClass; /** * @var string * @ORM\Column(type="string", length=255, nullable=false) */ protected $requiredIdentifiers; /** * @var string * @ORM\Column(type="string", length=255, nullable=true) */ protected $nullableClass; /** * @var string * @ORM\Column(type="string", length=255, nullable=true) */ protected $nullableIdentifiers; /** * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") * @ORM\Column(type="integer") */ protected $id; public function getId() { return $this->id; } }
现在,nullable
和 required
可以存储对任何其他 Doctrine 实体的引用。
使用 ReferenceHelper 设置和获取引用
使用 ReferenceHelper
,您现在可以设置和检索引用
use Vrok\References\Service\ReferenceHelper; $refHelper = $services->get(ReferenceHelper::class); $em = $services->get('Doctrine\ORM\EntityManager'); // the referenced object must have its identifiers (primary key columns) set, // e.g. be already persisted when using autoincrement ID $target = $em->getRepository(Target::class)->find(1); $source = new Source(); $refHelper->setReferencedObject($source, 'required', $target); $em->persist($source); $em->flush(); $sourceId = $source->getId(); // later: $loaded = $em->getRepository(Source::class)->find(sourceId); $refObject = $refHelper->getReferencedObject($source, 'required'); // $refObject == $target
限制引用目标类
要将 ReferenceHelper 限制为仅允许一个或某些类作为目标,请将类似以下内容添加到您的配置中
'reference_helper' => [ 'allowed_targets' => [ 'Entity\Source' => [ 'nullable' => [ 'Entity\Target', ], ], ], ],
现在,对于引用 nullable
,仅接受 Entity\Target
(及其子类)的实例。在 Entity\Source
上的每个其他引用仍然允许每个目标类。未在 allowed_targets
中列出的实体类接受每个引用的每个目标。
查询实体
由于 ${refName}Class
是与标识符分开的列,我们可以轻松地过滤引用类 Target
的每个对象
$em = $services->get('Doctrine\ORM\EntityManager'); $list = $em->getRepository(Entity\Source::class)->findBy([ 'requiredClass' => Entity\Target::class, ]);
我们还可以使用 ReferenceHelper
获取用于在 QueryBuilder 等中使用的过滤值
use Vrok\References\Service\ReferenceHelper; $refHelper = $services->get(ReferenceHelper::class); $em = $services->get('Doctrine\ORM\EntityManager'); $values = $refHelper->getClassFilterData(Entity\Source::class, 'required', Entity\Target::class); // $values == ['requiredClass' => 'Entity\Target'] $target = $em->getRepository(Entity\Target::class)->find(1); $values = $refHelper->getEntityFilterData(Entity\Source::class, 'required', $target); // $values == ['requiredClass' => 'Entity\Target', 'requiredIdentifiers' => '{"id":1}'] $values = $refHelper->getEntityFilterData(Entity\Source::class, 'required', null); // $values == ['requiredClass' => null, 'requiredIdentifiers' => null] // add filter to a QueryBuilder: $qb = $em->getRepository(Entity\Source::class)->createQueryBuilder('s'); $whereClause = []; foreach ($values as $column => $value) { $whereClause[] = "s.$column = :$column'; $qb->setParameter($column, $value); } $qb->andWhere(implode(' AND ', $whereClause));
由于 ReferenceHelper 必须知道要使用的别名(例如,如果您正在使用连接),并且是否要使用 "AND" 或 "OR" 将条件与先前条件组合,因此它无法为您将条件添加到给定的 QueryBuilder 中。您甚至可能希望同时搜索多个条件
SELECT * FROM Entity\Source s WHERE s.deleted = 0 AND (s.requiredClass = 'Entity\Target' OR s.requiredClass = 'Entity\OtherTarget')