我的 TYPO3 CMS 6.2 Extbase 扩展在多个控制器和操作方法和持久性之间传递对象时崩溃



我正在使用TYPO3 CMS 6.2.x LTS和Extension Builder编写TYPO3扩展。扩展应将 CSV 文件导入域模型,并在导入期间再填充两个模型。

CSV文件导入正常,但是以下控制器方法崩溃,我在解决问题时遇到问题。我相信问题的根源可能隐藏在我的插件调用第一个方法,但随后每个方法都直接转到下一个方法的事实中。Extbase 文档让我相信forward()不会返回到调用方法,我需要返回到原始方法以继续处理更多导入记录。

我的插件 URI 激活ImportMemberController->importAction() . ImportMemberController->importAction()传递一个$newPerson对象和一个$parameters数组,以PersonController->enrollAction()正常。 PersonController->enrollAction()传递$person$role$startTime$stopTime对象,HasRoleController->commissionAction()正常。 HasRoleController->commissionAction()在最后一行persistAll()崩溃,并显示以下消息。

致命错误:在 null 中调用成员函数 persistAll() typo3conf\ext\myextension\Classes\Controller\HasRoleController.php on 157路

包括 TCA 在内的配置通常与扩展生成器构建时相同。

下面是扩展的一些代码。对于长度,我深表歉意。

<?php
namespace MyNameSpaceMyextensionController;
/**
 * ImportMemberController
 */
class ImportMemberController extends TYPO3CMSExtbaseMvcControllerActionController {
    /**
     * importMemberRepository
     * 
     * @var MyNameSpaceMyextensionDomainRepositoryImportMemberRepository
     * @inject
     */
    protected $importMemberRepository = NULL;
    /**
     * personRepository
     *
     * @var MyNameSpaceMyextensionDomainRepositoryPersonRepository
     * @inject
     */
    protected $personRepository = NULL;
    /**
     * @var TYPO3CMSExtbasePersistenceGenericPersistenceManager
     * @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 = TYPO3CMSCoreUtilityGeneralUtility::makeInstance('TYPO3CMSExtbaseObjectObjectManager');
                    $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 = TYPO3CMSCoreUtilityGeneralUtility::makeInstance('MyNameSpace\Myextension\Controller\PersonController');
                    $newPersonController->enrollAction($newPerson, $parameters);
                }
            }
        }
        $this->redirect('list');
    }
}
<?php
namespace MyNameSpaceMyextensionController;
/**
 * PersonController
 */
class PersonController extends TYPO3CMSExtbaseMvcControllerActionController {
    /**
     * personRepository
     * 
     * @var MyNameSpaceMyextensionDomainRepositoryPersonRepository
     * @inject
     */
    protected $personRepository = NULL;
    /**
     * roleRepository
     *
     * @var MyNameSpaceMyextensionDomainRepositoryRoleRepository
     * @inject
     */
    protected $roleRepository = NULL;
    /**
     * action enroll
     *
     * @param MyNameSpaceMyextensionDomainModelPerson $person
     * @param mixed[] $parameters
     * @return void
     */
    public function enrollAction(MyNameSpaceMyextensionDomainModelPerson $person,
                                $parameters) {
        $person->setQualifiedUser(TRUE);
        $objectManager = TYPO3CMSCoreUtilityGeneralUtility::makeInstance('TYPO3CMSExtbaseObjectObjectManager');
        $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 = TYPO3CMSCoreUtilityGeneralUtility::makeInstance('MyNameSpace\Myextension\Controller\HasRoleController');
                $newHasRoleController->commissionAction($person, $role, $startTime, $stopTime);
            }
        }
    }
}
<?php
namespace MyNameSpaceMyextensionController;
/**
 * HasRoleController
 */
class HasRoleController extends TYPO3CMSExtbaseMvcControllerActionController {
    /**
     * hasRoleRepository
     * 
     * @var MyNameSpaceMyextensionDomainRepositoryHasRoleRepository
     * @inject
     */
    protected $hasRoleRepository = NULL;
    /**
     * @var TYPO3CMSExtbaseObjectObjectManager
     * @inject
     */
    protected $objectManager;
    /**
     * persistence manager
     *
     * @var TYPO3CMSExtbasePersistencePersistenceManagerInterface
     * @inject
     */
    protected $persistenceManager;
    /**
     * action commission
     *
     * @param MyNameSpaceMyextensionDomainModelPerson $person
     * @param MyNameSpaceMyextensionDomainModelRole $role
     * @param DateTime $startTime
     * @param DateTime $stopTime
     * @return void
     */
    public function commissionAction(MyNameSpaceMyextensionDomainModelPerson $person,
                                    MyNameSpaceMyextensionDomainModelRole $role,
                                    $startTime, $stopTime) {
        //$newHasRole = new MyNameSpaceMyextensionDomainModelHasRole(); // @todo: Remove this line.
        $objectManager = TYPO3CMSCoreUtilityGeneralUtility::makeInstance('TYPO3CMSExtbaseObjectObjectManager');
        $objectManager->get(TYPO3CMSExtbaseMvcControllerArguments::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(MyNameSpaceMyextensionDomainModelHasRole)
  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(TYPO3CMSExtbasePersistenceObjectStorage)[1008]
      private 'warning' => string 'You should never see this warning. If you do, you probably used PHP array functions like current() on the TYPO3CMSExtbasePersistenceObjectStorage. 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(TYPO3CMSExtbasePersistenceObjectStorage)[1045]
      private 'warning' => string 'You should never see this warning. If you do, you probably used PHP array functions like current() on the TYPO3CMSExtbasePersistenceObjectStorage. 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' (TYPO3CMSExtbaseDomainObjectAbstractDomainObject) => boolean false
  private '_cleanProperties' (TYPO3CMSExtbaseDomainObjectAbstractDomainObject) => 
    array (size=0)
      empty
$objectManager = object(TYPO3CMSExtbaseObjectObjectManager)
$person = object(KeystoneResearchSolutionsGrouproleDomainModelPerson)
$role = object(KeystoneResearchSolutionsGrouproleDomainModelRole)
$startTime = object(DateTime)
$stopTime = object(DateTime)

从对象管理器显式获取持久性管理器解决了这个问题。尽管持久性管理器注入已经存在于类的头部。

解决方案的线索来自Arek van Schaijk在findAll上对extbase中的非对象的评论,该解决方案的线索来自Arek van Schaijk的2015-05-26 14:18评论说:"这里唯一可能发生的事情是injectProductRepository()没有很好地注入您的存储库(对象)。下一条评论说,"所以基本上所有的注射都被缓存了,并且没有检查是否有新的注射。显然,在某些情况下,Extbase 注入机制不会接合。

以下是有效的函数代码:

/**
 * action commission
 *
 * @param MyNameSpaceMyextensionDomainModelPerson $person
 * @param MyNameSpaceMyextensionDomainModelRole $role
 * @param DateTime $startTime
 * @param DateTime $stopTime
 * @return void
 */
public function commissionAction(MyNameSpaceMyextensionDomainModelPerson $person,
                                 MyNameSpaceMyextensionDomainModelRole $role,
                                 $startTime, $stopTime) {
    $objectManager = TYPO3CMSCoreUtilityGeneralUtility::makeInstance('TYPO3CMSExtbaseObjectObjectManager');
    $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('TYPO3CMSExtbasePersistenceGenericPersistenceManager');
    $this->persistenceManager->persistAll();
}

实际上不需要手动保留对象,因为如果在每个操作结束时与存储库相关联,extbase 会自动保留对对象的更改。

您注入了持久性管理器,但没有清除所有缓存....您必须清除所有内容以反映新的注射。在某些情况下,甚至可以清除 typo3temp 文件夹。

要在不需要使用安装工具的情况下为BE中的选定用户添加Flush system caches图标,只需编辑所需的帐户并将其添加到其TSConfig

options.clearCache.system = 1

保存用户并通过按 F5 刷新整个 BE。

允许任何人清除系统缓存(尤其是在大型实例上)是一个相当糟糕的主意,因此仅对开发人员和聪明的管理员保留这种可能性。

最新更新