Search code examples
phpreflectiontypo3storagetypo3-9.x

"Class does not exist. Reflection failed." with lazy loading and object storages


I'm upgrading a website from TYPO3 8 to TYPO3 9

All the code was working well with TYPO3 8.
Now I have to adapt a lot as it came from even earlier TYPO3 (TCA, doctrine, ...) and throws some errors.

At the moment I have the problem for some pages I only get this error (in slight modifications):

(1/2) #1278450972 TYPO3\CMS\Extbase\Reflection\Exception\UnknownClassException

Class VendorName\VendorExtensionName\Domain\Model\TYPO3\CMS\Extbase\Persistence\ObjectStorage does not exist. Reflection failed.

I assume it is triggered by this code:

<?php
namespace VendorName\VendorExtensionName\Controller;
use TYPO3\CMS\Extbase\Annotation\Inject;

class AnsprechpartnerController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {

    /**
     * ansprechpartnerRepository
     *
     * @Inject
     * @var \VendorName\VendorExtensionName\Domain\Repository\AnsprechpartnerRepository
     */
    protected $ansprechpartnerRepository;

    [...]

    /**
     * action showDetail
     *
     * @return void
     */
    public function showDetailAction() {
        $pids = $this->settings['pids'];
        $this->settings['ansprechpartner'] = explode(',', $this->settings['ansprechpartner']);
        foreach ($this->settings['ansprechpartner'] as $uid) {
            $person = $this->ansprechpartnerRepository->findByUid($uid);  

    [...]

as this last line is in the debug stack.

The extension has 8 kinds of records which relate to each other. I assume because of this the relations are defined lazy and object storages are used.

<?php
namespace VendorName\VendorExtensionName\Domain\Model;
use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
/**
 *
 * @package vendor_extension_name
 *
 */
class Ansprechpartner extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {

[...]


/**
 * Organisationseinheit
 *
 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\VendorName\VendorExtensionName\Domain\Model\Organisation>
 * @Lazy
 */
protected $organisationseinheit;

/**
 * Dienstleistungen
 *
 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\VendorName\VendorExtensionName\Domain\Model\AnsprechpartnerDienstleistung>
 * @Lazy
 */
protected $dienstleistungen = NULL;

[...]

But here the order of the mixed up classes is reversed.
Nonetheless this might be the reason for the mixing/concatenating of the existing namespaces VendorName\VendorExtensionName\Domain\Model[\Ansprechpartner] and
\TYPO3\CMS\Extbase\Persistence\ObjectStorage to the strange class name
VendorName\VendorExtensionName\Domain\Model\TYPO3\CMS\Extbase\Persistence\ObjectStorage, which of course does not exist.


Edit:
insert the usage of
use TYPO3\CMS\Extbase\Annotation\Inject; and
use TYPO3\CMS\Extbase\Annotation\ORM\Lazy; instead of build in inject and lazy, which has no effect.


Edit 2:

Initialization of storages (example from the class above):

class Ansprechpartner extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{

    :
    /**
     * __construct
     *
     * @return Ansprechpartner
     */
    public function __construct() {
        $this->initStorageObjects();
    }

    /**
     * Initializes all ObjectStorage properties.
     *
     * @return void
     */
    protected function initStorageObjects() {
        $this->organisationseinheit = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
        $this->dienstleistungen = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
    }
    :

Solution

  • We found out, this is due to the changes within 9.x that relative Namespaces are now supported within Annotations and TypeHints.

    Before 9.x, Extbase Reflection always asumed absolute namespaces.

    If there is a Method with this signature, that worked before 9.x (which is a Bug) and does not work since 9.x anymore:

    public function setSomeStorage(TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage) {
    

    This has to be:

    public function setSomeStorage(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage) {