5

Scenario:

I have following model: Domain-Model

ContactPerson has a relation to FrontendUser and is the owning side of the relation. Now I have following problem:
I am activating/deactivating the FrontendUsers in a task, based on the ContactPersons which are active. When the FrontendUser is disabled or deleted the result of contactPerson->getFrontendUser() is null, even if both repositories ignoreEnableFields:

    /** @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,
        )
    );

Result: DebugResult

P.s.: $this->frontendUserRepository->findByUid(7); also doesn't work because it isn't using the query, but persistenceManager->getObjectByIdentifier(... which is of course ignoring the query-settings.

The problem is, in my real code I can't use findOneByUid(), because I can't get the integer-Value(uid) in the frontend_user field of the contact_person.

Any way to solve this without using a raw query to get the contact_person-row?


My (yes raw query) Solution:

Because I didn't want to write an own QueryFactory and I didn't want to add a redundant field to my contactPerson I solved it now with a raw statement. Maybe it can help someone with the same problem:

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();
    }

}
Aljoscha
  • 306
  • 3
  • 13

2 Answers2

8

Invoking repository directly

There are two aspects for the enable fields of table fe_users:

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

Have a look to some overview in the wiki page - it says 6.2, but it's still valid in most parts for 7.6 and 8 as well. However, this only works if the repository is invoked directly, but not if an entity is retrieved as part of another entity - in this case the repository is not used for nested entities.

Modify query settings for nested entities

Nested entities are retrieved implicitly - this happens in DataMapper::getPreparedQuery(DomainObjectInterface $parentObject, $propertyName). To adjust query settings for child entities, the QueryFactoryInterface implementation has to be overloaded.

Register an alternative implementation in ext_localconf.php (replace \Vendor\ExtensionName\Persistence\Generic\QueryFactory with the real class name of your extension):

$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
);

With new Typo3 versions (v8+), the registerImplementation method no longer works for QueryFactory. Instead, a XCLASS must be used to overwrite/extend the class:

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

Then inside the implementation:

<?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;
    }
}

Ceremony
  • 198
  • 2
  • 13
Oliver Hader
  • 4,093
  • 1
  • 25
  • 47
  • $querySettings->setIgnoreEnableFields(true); – Aljoscha Oct 12 '16 at 09:33
  • // if nothing else is given, all enableFields are ignored $querySettings->setIgnoreEnableFields(true); // define single fields to be ignored $querySettings->setEnableFieldsToBeIgnored(['disable']); The first one should disable all enable fields. But it only has effect on queries of the repository, not on the relation of some other model. – Aljoscha Oct 12 '16 at 09:35
  • 1
    Exactly, this only works if the repository is invoked directly, but not if an entity is retrieved as part of another entity - in this case the repository is not used for nested entities. I'll update the answer above to given an example on how to do that individually. – Oliver Hader Oct 12 '16 at 10:17
  • @OliverHader Any experience with 8.7.x? I cannot get fe_users that are disabled. Worked with 7.6.x – metaxos Mar 08 '18 at 16:01
0

My solution of this problem was to disable the "enablecolumns" in TCA definitions and deal this in the repository myself. Here an example of findAll method:

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();
}
Grony
  • 1
  • Disabling the section `$TCA['fe_users']['ctrl']['enablecolumns']` has a global effect on all handlers of frontend users, not only related to Extbase applications. Thus, this would probably modify the login behavior as well - disabled or expired user accounts still could be used to log into the according application. – Oliver Hader Mar 17 '18 at 09:24