vrok/ref-helper

支持与 Doctrine2 实体进行多态关联的实用工具

v1.2.0 2018-03-27 10:42 UTC

This package is auto-updated.

Last update: 2024-09-14 23:59:23 UTC


README

支持在 Zend Framework 3 中与 Doctrine 2 进行多态关联的库。

Build Status Coverage Status

许多应用程序具有多态关系,我们不知道(也不希望在事先知道)哪些实体可以分配给哪些(例如,哪个实体属于哪个)。例如,银行账户可能属于用户或组织,验证可能属于银行账户或用户。

为了支持这种松散耦合,我们将引用实体的类和形成主键的标识符(例如,自增键或复合键)分别存储在引用实体中。引用实体应保持简单 POPO,它们需要实现 Vrok\References\Entity\HasReferenceInterface,它由 Vrok\References\Entity\HasReferenceTrait 实现,以便重用。接口和特质支持一个实体上的多个引用,例如,引用创建者和所有者。

Vrok\References\Service\ReferenceHelper 通过提供设置和检索引用实体的函数来在此基础上构建。辅助工具还具有限制引用仅限于一个或某些目标类的功能。

使用方法

实体准备

  1. 在应存储对另一个对象引用的实体上实现 HasReferenceInterface,使用 HasReferenceTrait 以简化操作
  2. 通过定义每个引用的 $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;
    }
}

现在,nullablerequired 可以存储对任何其他 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')