如何在学说 2 中选择鉴别器列

2022-01-03 00:00:00 php symfony doctrine-orm dql discriminator

在运行下面的 DQL 时仅从原则 2 中选择鉴别器列时我需要一些帮助

I need some help when select only discriminator column from doctrine 2 when run the DQL below

SELECT p.type FROM AppBundleEntityProduct p

type 是实体 AppBundleEntityProduct

@ORMDiscriminatorColumn(name="type", type="smallint")`

@ORMDiscriminatorMap({
    "0" = "AppBundleEntityProduct",
    "1" = "AppBundleEntityProductSingleIssue",
    "2" = "AppBundleEntityProductCountBasedIssue",
    "3" = "AppBundleEntityProductTimeBasedIssue"
})

我知道 type 不是实体中的真正属性,但无论如何我可以这样做吗?

I know that type is not a real property in entity, but is there anyway for me to do that?

提前致谢!

在阅读了 2 天的 Doctrine 代码后,我决定覆盖 SqlWalker 并通过下面的代码片段创建新的 Hydrator

After 2 days for reading Doctrine codes, I decided to override SqlWalker and create new Hydrator by the snippets below

<?php

namespace ...;

use DoctrineORMQuerySqlWalker;

class CustomSqlWalker extends SqlWalker
{
    const FORCE_GET_DISCRIMINATOR_COLUMN = 'forceGetDiscriminatorColumn';
    const DISCRIMINATOR_CLASS_MAP = 'discriminatorClassMap';

    /**
     * {@inheritdoc}
     */
    public function walkSelectClause($selectClause)
    {
        $sql = parent::walkSelectClause($selectClause);
        $forceGetDiscriminatorColumn = $this->getQuery()->getHint(self::FORCE_GET_DISCRIMINATOR_COLUMN);
        if (empty($forceGetDiscriminatorColumn)) {
            return $sql;
        }

        foreach ($this->getQueryComponents() as $key => $queryComponent) {
            if (!in_array($key, $forceGetDiscriminatorColumn)) {
                continue;
            }

            $metadata = $queryComponent['metadata'];
            $discriminatorColumn = $metadata->discriminatorColumn['name'];
            $tableName = $metadata->table['name'];
            $tableAlias = $this->getSQLTableAlias($tableName, $key);
            $discriminatorColumnAlias = $this->getSQLColumnAlias($discriminatorColumn);
            $sql .= ", $tableAlias.$discriminatorColumn AS $discriminatorColumnAlias";
        }

        return $sql;
    }
}

定制保湿器

<?php

namespace ...;

use DoctrineORMInternalHydrationArrayHydrator;
use PDO;

class CustomHydrator extends ArrayHydrator
{
    /**
     * {@inheritdoc}
     */
    protected function hydrateAllData()
    {
        $result = array();

        $rootClassName = null;
        if (isset($this->_hints['forceGetDiscriminatorColumn']) &&
            isset($this->_hints['discriminatorClassMap'])) {
            $rootClassName = $this->_hints['discriminatorClassMap'];
        }

        while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
            foreach ($data as $key => $value) {
                if ($this->hydrateColumnInfo($key) != null ||
                    empty($rootClassName)) {
                    continue;
                }

                $metadata = $this->getClassMetadata($rootClassName);
                $discriminatorColumn = $metadata->discriminatorColumn;
                $fieldName = $discriminatorColumn['fieldName'];
                $type = $discriminatorColumn['type'];
                $this->_rsm->addScalarResult(
                    $key, $fieldName, $type
                );
            }
            $this->hydrateRowData($data, $result);
        }

        return $result;
    }
}

配置自定义水化器

orm:
    ...
    hydrators:
        CustomHydrator: YourNamespaceToCustomHydrator

最后一步

$query = $queryBuilder->getQuery();
$query->setHint(DoctrineORMQuery::HINT_CUSTOM_OUTPUT_WALKER, 'YourNamespaceToCustomSqlWalker');
$query->setHint(YourNamespaceToCustomSqlWalker::FORCE_GET_DISCRIMINATOR_COLUMN, array($rootAlias)); // this alias will be used in CustomSqlWalker class
$query->setHint(YourNamespaceToCustomSqlWalker::DISCRIMINATOR_CLASS_MAP, $this->getClassName()); // this full-qualify class name will be used in CustomHydrator class

$products = $query->getResult('CustomHydrator');

TL;DR

我知道这是一个非常复杂的解决方案(可能仅适用于我的场景),所以我希望有人能给我另一种简单的方法来解决这个问题,非常感谢!

TL;DR

I know this is a very complicated solution (may be just for my scenario), so I hope someone could give me another simple way to fix that, thanks so much!

推荐答案

没有直接访问鉴别器列.

There is no direct access to the discriminator column.

可能会发生特殊类型的实体应该被查询的情况.因为没有直接访问鉴别器列,Doctrine 提供了 INSTANCE OF 结构.

It may happen that the entities of a special type should be queried. Because there is no direct access to the discriminator column, Doctrine provides the INSTANCE OF construct.

您可以使用 INSTANCE OF DQL 如文档中所述.例如:

You can query for the type of your entity using the INSTANCE OF DQL as described in the docs. As example:

$query = $em->createQuery("SELECT product FROM AppBundleEntityAbstractProduct product WHERE product  INSTANCE OF AppBundleEntityProduct");
$products = $query->getResult();

希望能帮到你

相关文章