TYPO3 Extbase: как получить отключенный связанный объект без необработанного sql-запроса?

#typo3 #extbase

#typo3 #extbase

Вопрос:

Сценарий:

У меня есть следующая модель: Модель домена

ContactPerson имеет отношение к интерфейсному пользователю и является стороной-владельцем отношения. Теперь у меня следующая проблема:
я активирую / деактивирую интерфейсных пользователей в задаче на основе активных контактных лиц. Когда интерфейсный пользователь отключен или удален, результат ContactPerson-> getFrontendUser() равен нулю, даже если оба репозитория игнорируют поля:

     /** @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);
    TYPO3CMSExtbaseUtilityDebuggerUtility::var_dump(
        array(
            '$debugContactPerson' => $debugContactPerson,
            '$debugFrontendUser' => $debugFrontendUser,
        )
    );
  

Результат: DebugResult

P.s.: $this->frontendUserRepository->findByUid(7); также не работает, потому что он не использует запрос, но persistenceManager->getObjectByIdentifier(... , конечно, игнорирует настройки запроса.

Проблема в том, что в моем реальном коде я не могу использовать findOneByUid(), потому что я не могу получить целочисленное значение (uid) в поле frontend_user поля contact_person .

Есть ли способ решить эту проблему без использования необработанного запроса для получения строки contact_person?


Мое (да, необработанный запрос) решение:

Поскольку я не хотел писать собственный QueryFactory и не хотел добавлять избыточное поле к моему контактеру, я решил это сейчас с помощью необработанного оператора. Может быть, это может помочь кому-то с той же проблемой:

 class FrontendUserRepository extends TYPO3CMSExtbaseDomainRepositoryFrontendUserRepository
{
    /**
     * @param VendorExtKeyDomainModelContactPerson $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();
    }

}
  

Комментарии:

1. Я опубликовал отчет об ошибке для TYPO3: forge.typo3.org/issues/84955

Ответ №1:

Прямой вызов репозитория

Для полей включения таблицы есть два аспекта fe_users :

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

Посмотрите на некоторый обзор на странице wiki — там написано 6.2, но он по-прежнему действителен в большинстве частей для 7.6 и 8. Однако это работает только в том случае, если репозиторий вызывается напрямую, но не в том случае, если объект извлекается как часть другого объекта — в этом случае репозиторий не используется для вложенных объектов.

Измените настройки запроса для вложенных объектов

Вложенные объекты извлекаются неявно — это происходит в DataMapper::getPreparedQuery(DomainObjectInterface $parentObject, $propertyName) . Чтобы настроить параметры запроса для дочерних объектов, QueryFactoryInterface реализация должна быть перегружена.

Зарегистрируйте альтернативную реализацию в ext_localconf.php (замените VendorExtensionNamePersistenceGenericQueryFactory на реальное имя класса вашего расширения):

 $extbaseObjectContainer = TYPO3CMSCoreUtilityGeneralUtility::makeInstance(
    TYPO3CMSExtbaseObjectContainerContainer::class
);
$extbaseObjectContainer->registerImplementation(
    TYPO3CMSExtbasePersistenceGenericQueryFactoryInterface::class,
    VendorExtensionNamePersistenceGenericQueryFactory::class
);
  

С новыми версиями Typo3 (v8 ) метод registerImplementation больше не работает для QueryFactory. Вместо этого для перезаписи / расширения класса необходимо использовать XCLASS:

 $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][TYPO3CMSExtbasePersistenceGenericQueryFactory::class] = [
    'className' => VendorExtensionNamePersistenceGenericQueryFactory::class,
];
  

Затем внутри реализации:

 <?php
namespace VendorExtensionNamePersistenceGeneric;
use TYPO3CMSExtbaseDomainModelFrontendUser;

class QueryFactory extends TYPO3CMSExtbasePersistenceGenericQueryFactory {
    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;
    }
}

  

Комментарии:

1. $querySettings-> setIgnoreEnableFields(true);

2. // если больше ничего не указано, все разрешаемые поля игнорируются $querySettings-> setIgnoreEnableFields(true); // определите отдельные поля, которые будут игнорироваться $querySettings-> setEnableFieldsToBeIgnored([‘disable’]); Первый должен отключить все разрешаемые поля. Но это влияет только на запросы репозитория, а не на отношение какой-либо другой модели.

3. Точно, это работает только в том случае, если репозиторий вызывается напрямую, но не в том случае, если объект извлекается как часть другого объекта — в этом случае репозиторий не используется для вложенных объектов. Я обновлю приведенный выше ответ, чтобы привести пример того, как это сделать по отдельности.

4. @OliverHader Есть опыт работы с 8.7.x? Я не могу получить fe_users, которые отключены. Работал с 7.6.x

Ответ №2:

Мое решение этой проблемы состояло в том, чтобы отключить «enablecolumns» в определениях TCA и разобраться с этим в репозитории самостоятельно. Вот пример метода 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();
}
  

Комментарии:

1. Отключение раздела $TCA['fe_users']['ctrl']['enablecolumns'] оказывает глобальное влияние на все обработчики интерфейсных пользователей, а не только на приложения Extbase. Таким образом, это, вероятно, также изменит поведение входа в систему — отключенные или просроченные учетные записи пользователей все еще могут использоваться для входа в соответствующее приложение.