В моем расширении TYPO3 CMS 6.2 Extbase происходит сбой при передаче объектов между несколькими контроллерами и методами действий и постоянством

Я пишу расширение TYPO3, используя TYPO3 CMS 6.2.x LTS и Extension Builder. Расширение должно импортировать файл CSV в модель предметной области и заполнять еще две модели во время импорта.

CSV-файл импортируется нормально, но следующий метод контроллера дает сбой, и мне не удается решить проблему. Я считаю, что источник проблемы может быть скрыт в том факте, что мой плагин вызывает первый метод, но затем каждый метод переходит непосредственно к следующему методу. Документация Extbase наводит меня на мысль, что forward() не вернется к вызывающему методу, и мне нужно вернуться к исходному методу, чтобы продолжить обработку большего количества записей импорта.

Мой URI плагина активирует ImportMemberController->importAction(). ImportMemberController->importAction() передает $newPerson объект и массив $parameters в PersonController->enrollAction() ok. PersonController->enrollAction() передает объекты $person, $role, $startTime и $stopTime в HasRoleController->commissionAction() нормально. HasRoleController->commissionAction() вылетает в последней persistAll() строке со следующим сообщением.

Неустранимая ошибка: вызов функции-члена persistAll () с нулевым значением в typo3conf \ ext \ myextension \ Classes \ Controller \ HasRoleController.php в строке 157

Конфигурации, включая TCA, обычно остаются неизменными с момента их создания с помощью Extension Builder.

Вот код расширения. Мои извинения за длину.

<?php
namespace MyNameSpace\Myextension\Controller;
/**
 * ImportMemberController
 */
class ImportMemberController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {

    /**
     * importMemberRepository
     * 
     * @var \MyNameSpace\Myextension\Domain\Repository\ImportMemberRepository
     * @inject
     */
    protected $importMemberRepository = NULL;

    /**
     * personRepository
     *
     * @var \MyNameSpace\Myextension\Domain\Repository\PersonRepository
     * @inject
     */
    protected $personRepository = NULL;

    /**
     * @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
     * @inject
     */
    protected $persistenceManager;

    /**
     * action import
     *
     * @return void
     */
    public function importAction() {
        $importMembers = $this->importMemberRepository->findAll();
        foreach ($importMembers as $importMember) {

            // Assess the qualification of this import person.
            $newQualification = TRUE;
            if ($importMember->getEmail() == "") {
                $newQualification = FALSE;
            }
            elseif ($importMember->getFirstName() == "") {
                $newQualification = FALSE;
            }
            elseif ($importMember->getLastName() == "") {
                $newQualification = FALSE;
            }

            // Determine whether this person is already in the personRepository.
            $queryResult = $this->personRepository->findBySomeNumber($importMember->getSomeNumber());
            if ($queryResult->count() > 0) {
                $person = $queryResult->getFirst();
                // Update changes to an existing person's specified properties.
                if ($person->getFamilyName() != $importMember->getLastName()) {
                    $person->setFamilyName($importMember->getLastName());
                }
                if ($person->getFirstName() != $importMember->getFirstName()) {
                    $person->setFirstName($importMember->getFirstName());
                }
                if ($person->getEmailAddress() != $importMember->getEmail()) {
                    $person->setEmailAddress($importMember->getEmail());
                }
                $this->personRepository->update($person);
                // Obtain the qualification status of this existing person.
                $existingQualification = $person->getQualifiedUser();
                // Disenroll this existing person if they no longer qualify.
                if ($existingQualification && !$newQualification) {
                    $person->setQualifiedUser(FALSE);
                }
                // Else enroll this existing person if they qualify after being unqualified.
                elseif (!$existingQualification && $newQualification) {
                    $person->setQualifiedUser(TRUE); // @todo: Reevaluate the need for this instruction.
                }
                // Else act if this existing person qualifies but changed  Office.
                elseif ($existingQualification && $newQualification && 2==1) {
                    // @todo: Later.
                }
            }
            else {
                // Act if this new import person qualifies.
                if ($newQualification) {
                    // Enter this new import person into personRepository.
                    $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
                    $newPerson = $objectManager->get('MyNameSpace\\Myextension\\Domain\\Model\\Person');
                    $newPerson->setFamilyName($importMember->getLastName());
                    $newPerson->setFirstName($importMember->getFirstName());
                    $newPerson->setSomeNumber($importMember->getSomeNumber());
                    $newPerson->setEmailAddress($importMember->getEmail());
                    $this->personRepository->add($newPerson);
                    $this->persistenceManager->persistAll();
                    // Enroll this new import person.
                    if ($importMember->getDate()) {
                        $startTime = $importMember->getDate();
                    }
                    else {
                        $startTime = new \DateTime();
                    }
                    if ($importMember->getPaidThru()) {
                        $stopTime = $importMember->getPaidThru();
                    }
                    else {
                        $stopTime = new \DateTime();
                        $stopTime->modify('+100 years');
                    }
                    $parameters = array(
                        'title' => ' Office '.$importMember->getOffice().' Member',
                        'startTime' => $startTime,
                        'stopTime' => $stopTime
                    );
                    $newPersonController = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('MyNameSpace\\Myextension\\Controller\\PersonController');
                    $newPersonController->enrollAction($newPerson, $parameters);
                }
            }
        }
        $this->redirect('list');
    }
}

<?php
namespace MyNameSpace\Myextension\Controller;
/**
 * PersonController
 */
class PersonController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {

    /**
     * personRepository
     * 
     * @var \MyNameSpace\Myextension\Domain\Repository\PersonRepository
     * @inject
     */
    protected $personRepository = NULL;

    /**
     * roleRepository
     *
     * @var \MyNameSpace\Myextension\Domain\Repository\RoleRepository
     * @inject
     */
    protected $roleRepository = NULL;

    /**
     * action enroll
     *
     * @param \MyNameSpace\Myextension\Domain\Model\Person $person
     * @param mixed[] $parameters
     * @return void
     */
    public function enrollAction(\MyNameSpace\Myextension\Domain\Model\Person $person,
                                $parameters) {
        $person->setQualifiedUser(TRUE);
        $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
        $this->roleRepository = $objectManager->get('MyNameSpace\\Myextension\\Domain\\Repository\\RoleRepository');
        if ($parameters['title']) {
            $queryResult = $this->roleRepository->findByTitle($parameters['title']);
            if ($queryResult->count() > 0) {
                $role = $queryResult->getFirst();
                if ($parameters['startTime']) {
                    $startTime = $parameters['startTime'];
                } else {
                    $startTime = new \DateTime();
                }
                if ($parameters['stopTime']) {
                    $stopTime = $parameters['stopTime'];
                } else {
                    $stopTime = new \DateTime();
                    $stopTime->modify('+100 years');
                }
                $newHasRoleController = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('MyNameSpace\\Myextension\\Controller\\HasRoleController');
                $newHasRoleController->commissionAction($person, $role, $startTime, $stopTime);
            }
        }
    }
}

<?php
namespace MyNameSpace\Myextension\Controller;
/**
 * HasRoleController
 */
class HasRoleController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {

    /**
     * hasRoleRepository
     * 
     * @var \MyNameSpace\Myextension\Domain\Repository\HasRoleRepository
     * @inject
     */
    protected $hasRoleRepository = NULL;

    /**
     * @var \TYPO3\CMS\Extbase\Object\ObjectManager
     * @inject
     */
    protected $objectManager;

    /**
     * persistence manager
     *
     * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
     * @inject
     */
    protected $persistenceManager;

    /**
     * action commission
     *
     * @param \MyNameSpace\Myextension\Domain\Model\Person $person
     * @param \MyNameSpace\Myextension\Domain\Model\Role $role
     * @param \DateTime $startTime
     * @param \DateTime $stopTime
     * @return void
     */
    public function commissionAction(\MyNameSpace\Myextension\Domain\Model\Person $person,
                                    \MyNameSpace\Myextension\Domain\Model\Role $role,
                                    $startTime, $stopTime) {
        //$newHasRole = new \MyNameSpace\Myextension\Domain\Model\HasRole(); // @todo: Remove this line.
        $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
        $objectManager->get(\TYPO3\CMS\Extbase\Mvc\Controller\Arguments::class);
        $newHasRole = $objectManager->get('MyNameSpace\\Myextension\\Domain\\Model\\HasRole');
        //$newHasRole = $this->objectManager->get('MyNameSpace\\Myextension\\Domain\\Model\\HasRole');
        $newHasRole->setStartTime($startTime);
        $newHasRole->setStopTime($stopTime);
        $newHasRole->addPerson($person);
        //$newHasRole->setPerson($person); // @todo: Remove this line.
        $newHasRole->addRole($role);
        //$newHasRole->setRole($person); // @todo: Remove this line.
        $this->hasRoleRepository = $objectManager->get('MyNameSpace\\Myextension\\Domain\\Repository\\HasRoleRepository');
        //$this->hasRoleRepository = $this->objectManager->get('MyNameSpace\\Myextension\\Domain\\Repository\\HasRoleRepository');
        $this->hasRoleRepository->add($newHasRole);
        $this->persistenceManager->persistAll();
    }
}

В момент сбоя переменные в локальной области видимости:

$newHasRole = object(MyNameSpace\Myextension\Domain\Model\HasRole)
  protected 'startTime' => 
    object(DateTime)[834]
      public 'date' => string '1993-11-29 19:00:00.000000' (length=26)
      public 'timezone_type' => int 3
      public 'timezone' => string 'America/New_York' (length=16)
  protected 'stopTime' => 
    object(DateTime)[982]
      public 'date' => string '2116-03-10 17:55:43.000000' (length=26)
      public 'timezone_type' => int 3
      public 'timezone' => string 'America/New_York' (length=16)
  protected 'person' => 
    object(TYPO3\CMS\Extbase\Persistence\ObjectStorage)[1008]
      private 'warning' => string 'You should never see this warning. If you do, you probably used PHP array functions like current() on the TYPO3\CMS\Extbase\Persistence\ObjectStorage. To retrieve the first result, you can use the rewind() and current() methods.' (length=228)
      protected 'storage' => 
        array (size=1)
          '000000007303096700000000080231e7' => 
            array (size=2)
              ...
      protected 'isModified' => boolean true
      protected 'addedObjectsPositions' => 
        array (size=1)
          '000000007303096700000000080231e7' => int 1
      protected 'removedObjectsPositions' => 
        array (size=0)
          empty
      protected 'positionCounter' => int 1
  protected 'role' => 
    object(TYPO3\CMS\Extbase\Persistence\ObjectStorage)[1045]
      private 'warning' => string 'You should never see this warning. If you do, you probably used PHP array functions like current() on the TYPO3\CMS\Extbase\Persistence\ObjectStorage. To retrieve the first result, you can use the rewind() and current() methods.' (length=228)
      protected 'storage' => 
        array (size=1)
          '0000000073030eea00000000080231e7' => 
            array (size=2)
              ...
      protected 'isModified' => boolean true
      protected 'addedObjectsPositions' => 
        array (size=1)
          '0000000073030eea00000000080231e7' => int 1
      protected 'removedObjectsPositions' => 
        array (size=0)
          empty
      protected 'positionCounter' => int 1
  protected 'uid' => null
  protected '_localizedUid' => null
  protected '_languageUid' => null
  protected '_versionedUid' => null
  protected 'pid' => null
  private '_isClone' (TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject) => boolean false
  private '_cleanProperties' (TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject) => 
    array (size=0)
      empty

$objectManager = object(TYPO3\CMS\Extbase\Object\ObjectManager)
$person = object(KeystoneResearchSolutions\Grouprole\Domain\Model\Person)
$role = object(KeystoneResearchSolutions\Grouprole\Domain\Model\Role)
$startTime = object(DateTime)
$stopTime = object(DateTime)

person Andrew    schedule 11.03.2016    source источник
comment
Вы внедрили диспетчер сохраняемости, но не очистили все кеши .... вы должны очистить действительно ВСЕ, чтобы отразить новые инъекции. В некоторых случаях даже очистить папку typo3temp   -  person biesior    schedule 11.03.2016
comment
Спасибо! Я перехожу к важным действиям TYPO3 Install Tool и очищаю все кеши, а затем очищаю все соответствующие временные файлы перед каждым запуском отладки. Я пропустил подготовительный этап? Есть ли четкие инструкции в Extbase?   -  person Andrew    schedule 11.03.2016


Ответы (3)


Явное получение диспетчера сохраняемости из диспетчера объектов решило проблему. И это несмотря на то, что инъекция Persistence Manager уже присутствует во главе класса.

Ключ к разгадке решения был получен в отчете Арека ван Шайка 2015-05- 26 14:18, комментарий в findAll для не объекта в extbase говоря: «Единственное, что может здесь происходить, это то, что injectProductRepository() плохо внедрил ваш репозиторий (объект)». И следующий комментарий гласит: «Итак, в основном все инъекции кэшируются, и нет проверки, есть ли новые инъекции». По-видимому, в некоторых ситуациях не задействуется механизм внедрения Extbase.

Вот код функции, которая сработала:

/**
 * action commission
 *
 * @param \MyNameSpace\Myextension\Domain\Model\Person $person
 * @param \MyNameSpace\Myextension\Domain\Model\Role $role
 * @param \DateTime $startTime
 * @param \DateTime $stopTime
 * @return void
 */
public function commissionAction(\MyNameSpace\Myextension\Domain\Model\Person $person,
                                 \MyNameSpace\Myextension\Domain\Model\Role $role,
                                 $startTime, $stopTime) {
    $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
    $newHasRole = $objectManager->get('MyNameSpace\\Myextension\\Domain\\Model\\HasRole');
    $newHasRole->setStartTime($startTime);
    $newHasRole->setStopTime($stopTime);
    $newHasRole->addPerson($person);
    $newHasRole->addRole($role);
    $this->hasRoleRepository = $objectManager->get('MyNameSpace\\Myextension\\Domain\\Repository\\HasRoleRepository');
    $this->hasRoleRepository->add($newHasRole);
    $this->persistenceManager = $objectManager->get('TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager');
    $this->persistenceManager->persistAll();
}
person Andrew    schedule 13.03.2016

На самом деле не должно быть необходимости вручную сохранять объект, поскольку extbase автоматически сохраняет изменения в объектах, если они связаны с репозиторием в конце каждого действия.

person sven    schedule 11.03.2016
comment
Я согласен с вами в теории. При сохранении вручную добавляются накладные расходы, и мне придется импортировать и обрабатывать более 20000 записей на регулярной основе. Однако более ранние версии кода не отслеживали и не хранили UID для вновь созданных объектов Person и HasRole. У вас есть альтернатива, которая может решить эту проблему? - person Andrew; 11.03.2016
comment
Нужны ли вам uid для дальнейшей логики в том же вызове действия? - person sven; 11.03.2016
comment
Хм. importAction () вызовет enrollAction () один раз для каждого человека, но enrollAction () может вызывать CommissionAction () несколько раз для каждого человека; затем цикл повторяется для следующего человека. Более ранняя версия кода успешно сохраняла объекты HasRole в базе данных, но их идентификаторы Person были равны 1 во всех записях, а не соответствовали фактическим UID каждого человека. - person Andrew; 11.03.2016

Вы внедрили диспетчер сохраняемости, но не очистили все кеши .... вы должны очистить действительно ВСЕ, чтобы отразить новые инъекции. В некоторых случаях даже очистите папку typo3temp.

Чтобы добавить значок Flush system caches для выбранных пользователей в BE без использования Install Tool, просто отредактируйте необходимую учетную запись и добавьте ее в ее TSConfig:

options.clearCache.system = 1

Сохраните пользователя и обновите всю ВЕ, нажав F5.

Довольно плохая идея позволять кому-либо очищать системные кеши (особенно на больших экземплярах), поэтому оставьте эту возможность только для разработчиков и умных администраторов.

person biesior    schedule 11.03.2016
comment
Очистка кешей системы не сработала. Программа аварийно завершает работу при выполнении той же инструкции persistAll () с теми же результатами для локальных переменных в области видимости. - person Andrew; 11.03.2016
comment
Что ж, вам нужно отладить себя, почему ваш диспетчер сохраняемости имеет значение null Я даже не знаю, какая строка в вашем примере 157;) Call to a member function persistAll() on null ... on line 157 - person biesior; 11.03.2016
comment
Строка 157 - это строка $this->persistenceManager->persistAll(); в конце образца. Спасибо за комментарии, я продолжу отладку. - person Andrew; 12.03.2016
comment
первый шаг к отладке - if(is_null($this->persistenceManager)) die('persistence manager is null!); - person biesior; 12.03.2016