TYPO3 Extbase:如何获取已禁用的相关对象,而不使用原始SQL查询?

5

场景:

我有以下模型:Domain-Model

ContactPerson与FrontendUser有关系,并且是关系的拥有方。现在我遇到了以下问题:
我正在根据处于活动状态的ContactPersons激活/停用FrontendUsers。当FrontendUser被禁用或删除时,即使两个存储库都忽略enable字段,contactPerson->getFrontendUser()的结果也为null:

    /** @var Typo3QuerySettings $querySettings */
    $querySettings = $this->objectManager->get(Typo3QuerySettings::class);
    $querySettings->setIgnoreEnableFields(true);
    $querySettings->setRespectStoragePage(false);
    $this->frontendUserRepository->setDefaultQuerySettings($querySettings);

    $debugContactPerson = $this->contactPersonRepository->findOneByContactPersonIdAndIncludeDeletedAndHidden('634');
    $debugFrontendUser = $this->frontendUserRepository->findOneByUid(7);
    \TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
        array(
            '$debugContactPerson' => $debugContactPerson,
            '$debugFrontendUser' => $debugFrontendUser,
        )
    );

结果:DebugResult 附注:$this->frontendUserRepository->findByUid(7);也不起作用,因为它没有使用查询,而是使用persistenceManager->getObjectByIdentifier(...,当然忽略了查询设置。
问题在于,在我的真实代码中,我无法使用findOneByUid(),因为我无法获取contact_person字段中的整数值(uid)。
有没有办法在不使用原始查询获取contact_person行的情况下解决这个问题?

我的(是的,原始查询)解决方案:

因为我不想编写自己的QueryFactory,也不想向我的contactPerson添加冗余字段,所以我现在使用了一个原始语句来解决这个问题。也许它可以帮助有同样问题的人:
class FrontendUserRepository extends \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository
{
    /**
     * @param \Vendor\ExtKey\Domain\Model\ContactPerson $contactPerson
     * @return Object
     */
    public function findByContactPersonByRawQuery(ContactPerson $contactPerson){
        $query = $this->createQuery();

        $query->statement(
            "SELECT fe_users.* FROM fe_users" .
            " LEFT JOIN tx_extkey_domain_model_contactperson contact_person ON contact_person.frontend_user = fe_users.uid" .
            " WHERE contact_person.uid = " . $contactPerson->getUid()
        );
        return $query->execute()->getFirst();
    }

}

我在TYPO3上发布了一个错误报告:https://forge.typo3.org/issues/84955 - feeela
2个回答

8

直接调用仓库

fe_users表的启用字段有两个方面:

  • $querySettings->setIgnoreEnableFields(true);
  • $querySettings->setEnableFieldsToBeIgnored(['disable']);

维基页面中可以了解一些概览-它说的是6.2版本,但大部分至今在7.6和8版本中依然有效。但是,这仅在直接调用存储库时有效,如果作为另一个实体的一部分检索到实体,则不使用存储库处理嵌套实体。

修改嵌套实体的查询设置

嵌套实体会隐式地被检索-这发生在DataMapper::getPreparedQuery(DomainObjectInterface $parentObject, $propertyName)中。 要为子实体调整查询设置,必须重载QueryFactoryInterface实现。

ext_localconf.php中注册替代实现(将\Vendor\ExtensionName\Persistence\Generic\QueryFactory替换为您扩展的实际类名):

$extbaseObjectContainer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
    \TYPO3\CMS\Extbase\Object\Container\Container::class
);
$extbaseObjectContainer->registerImplementation(
    \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface::class,
    \Vendor\ExtensionName\Persistence\Generic\QueryFactory::class
);

在新的 Typo3 版本(v8+)中,registerImplementation 方法不再适用于 QueryFactory。相反,必须使用 XCLASS 来覆盖/扩展该类:

$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactory::class] = [
    'className' => \Vendor\ExtensionName\Persistence\Generic\QueryFactory::class,
];

接着在实现中:

<?php
namespace \Vendor\ExtensionName\Persistence\Generic;
use TYPO3\CMS\Extbase\Domain\Model\FrontendUser;

class QueryFactory extends \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactory {
    public function create($className) {
        $query = parent::create($className);
        if (is_a($className, FrontendUser::class, true)) {
            // @todo Find a way to configure that more generic
            $querySettings = $query->getQuerySettings();
            $querySettings->setIgnoreEnableFields(true);
            // ... whatever you need to adjust in addition ...
        }
        return $query;
    }
}


$querySettings->setIgnoreEnableFields(true); $querySettings->setIgnoreEnableFields(true); - Aljoscha
// 如果没有给出其他内容,则所有的enableFields都将被忽略 $querySettings->setIgnoreEnableFields(true);// 定义要忽略的单个字段 $querySettings->setEnableFieldsToBeIgnored(['disable']);第一个将禁用所有的enable字段。但它只对存储库的查询产生影响,而不会影响其他模型的关系。 - Aljoscha
1
确切地说,这仅在直接调用存储库时有效,但如果作为另一个实体的一部分检索实体,则不适用于嵌套实体-在这种情况下,存储库不用于嵌套实体。我将更新上面的答案,以便提供如何单独执行此操作的示例。 - Oliver Hader
@OliverHader 你有8.7.x的经验吗?我无法获取已禁用的fe_users。之前使用7.6.x是可以的。 - metaxos

0
我的解决方案是在TCA定义中禁用“enablecolumns”,并在存储库中自己处理。以下是findAll方法的示例:
public function findAll($ignoreEnableFields = false) {
    $query = $this->createQuery();
    if (!$ignoreEnableFields) {
        $currTime = time();
        $query->matching(
            $query->logicalAnd(
                $query->equals("hidden", 0),
                $query->logicalOr(
                    $query->equals("starttime", 0),
                    $query->lessThanOrEqual("starttime", $currTime)
                ),
                $query->logicalOr(
                    $query->equals("endtime", 0),
                    $query->greaterThanOrEqual("endtime", $currTime)
                )
            )
        );
    }
    return $query->execute();
}

禁用 $TCA['fe_users']['ctrl']['enablecolumns'] 部分会对所有前端用户处理程序产生全局影响,不仅限于 Extbase 应用程序。因此,这可能会修改登录行为 - 禁用或过期的用户帐户仍然可以用于登录相应的应用程序。 - Oliver Hader

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接