在extbase扩展中,如何从调度程序任务访问持久层?

时间:2014-04-14 18:57:21

标签: typo3 extbase typo3-6.1.x

标题中有点学术性的声音实际上非常简单:我已经设置了一个TYPO3 6.1 extbase扩展,我已配备了调度程序任务。该任务应该导入CSV文件并将其保存到扩展的数据库字段中。

但是如何告诉调度程序任务使用扩展模型等并将接收到的数据保存到持久层?

我已经看到了类似问题的答案:Execute repository functions in scheduler task我认为它指出了正确的方法,但我认为需要一个完整的例子来开始理解依赖注入的工作原理。

2 个答案:

答案 0 :(得分:13)

首先,您必须考虑性能方面:

如果要插入大量数据,则不应将Extbase持久性用于此类任务。因为如果这样做,它将为您要插入的每一行生成一个对象,并立即将其保留。这非常慢并且占用大量内存。

如果您没有太多数据或拆分作业(例如,每个调度程序运行执行100个导入作业),则使用Extbase持久性。

你可以在CommandController上下文中同时使用它们,并且由于CommandControllers是直接设置的,你应该为它们而不是自己的Scheduler任务。

使用Extbase持久性

在CommandController中,注入您的存储库:

/**
 * myRepository
 *
 * @var \Venor\Myext\Domain\Repository\MyRepository
 * @inject
 */
protected $myRepository

然后遍历要导入的行(foreach)并为每行创建一个新对象并将其添加到存储库中:

 $myObject = $this->objectManager->get('Vendor\Myext\Domain\Model\MyModel');
 $myObject->setProperty('foo');
 $myObject->setOtherProperty('bar');
 $this->myRepository->add($myObject);

要将对象实际保存到数据库,您需要保留它们。所以你也注入了persistenceManager:

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

并使用它:

 $this->persistenceManager->persistAll();

您不应该为每个对象执行此操作(出于性能原因);但是出于内存使用的原因,你不应该等到数千个对象持续存在之后。所以你只需要在你的foreach循环中插入一个迭代器,并在每个20,40或任何循环中持续存在。

请不要忘记调度程序在后端上下文中工作,因此必须module.tx_yourext提供TypoScript。如果您想与应用的前端部分共享相同的设置/ storagePid,请使用

module.tx_yourext.persistence < plugin.tx_yourext.persistence
[...]

TypoScript需要出现在您网站的根页面中,以便后端模块/ CommandControllers使用它们。我建议你将这些内容添加到myext / Configuration / TypoScript / setup.txt中,并将扩展的静态模板添加到根页面。

使用DataHandler

TYPO3 DataHandler(以前称为TCEmain)是TYPO3后端用于插入和修改数据库记录的引擎。它非常强大。

在循环中创建一个包含所有数据的数组,而不是对象。第一个数组索引是表,下一个级别是受影响的记录,其中NEW表示创建新记录。然后,您只需设置具有所需值的表的每个字段

    $data = array();
    $data['be_users']['NEW'] = array(
        'pid' => 0,
        'username' => $staffMember['IDPerson'],
        'password' => md5(GeneralUtility::generateRandomBytes(40)), // random password
        'usergroup' => '1,2',
        'email' => $staffMember['Email'],
        'realName' => $staffMember['Nachname'] . ' ' . $staffMember['Vorname'],
        'lang' => 'de',
    );

现在您可以创建一个DataHandler实例并保留更改:

    /** @var $tce t3lib_TCEmain */
    $tce = GeneralUtility::makeInstance('TYPO3\CMS\Core\DataHandling\DataHandler');
    $tce->bypassAccessCheckForRecords = TRUE;
    $tce->start($data, array());
    $tce->admin = TRUE;
    $tce->process_datamap();
    $newRecordsUidArray = $tce->substNEWwithIDs['NEW'];

请注意$tce->admin = TRUE行。这向DataHandler建议管理员正在执行该操作。这很方便,因为您不必为Scheduler用户设置允许的排除字段,也可以将记录插入PID 0.但这可能存在安全漏洞,因此请仔细考虑其用法。

DataHandler正确记录插入/更新的记录,可以还原等等。您可以找到一些示例(例如添加图片,解析MM关系)here。在这种情况下,所有与DataHandler相关的函数都被移动到一个外部存储库类,如上所述注入CommandController(它只是在Extbase约定中命名)。

可以找到DataHandler函数的一个很好的概述here

答案 1 :(得分:2)

除了lorenz的回答:初学者指南设置命令控制器调度程序任务:

我的例子是导入任务。根据需要更改名称部分“导入”。

创建一个新文件EXT:Classes / Controller / ImportCommandController.php

    <?php
    namespace NAMESPACE\Myextension\Controller;

    /***************************************************************
     *  Copyright notice
     *
     *  (c) 2014 
     *  All rights reserved
     *
     *  This script is part of the TYPO3 project. The TYPO3 project is
     *  free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation; either version 3 of the License, or
     *  (at your option) any later version.
     *
     *  The GNU General Public License can be found at
     *  http://www.gnu.org/copyleft/gpl.html.
     *
     *  This script is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *
     *  This copyright notice MUST APPEAR in all copies of the script!
     ***************************************************************/

    /**
     *
     *
     * @package Myextension
     * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3 or later
     *
     */
    class ImportCommandController extends \TYPO3\CMS\Extbase\Mvc\Controller\CommandController {

        /**
         * itemRepository
         *
         * @var \NAMESPACE\Myextension\Domain\Repository\ItemRepository
         * @inject
         */
        protected $itemRepository;

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


        /**
         *
         * @param \integer $storagePid
         * @param \string $url
         *
         * @return bool
         */
        // very nice: parameters will be fields in the scheduler!
        public function importCommand($storagePid = 0,$url = NULL) {

            $source = utf8_encode(utf8_encode(file_get_contents($url)));

            // set storage page ourselves
            // not sure if really necessary

            $querySettings = $this->itemRepository->createQuery()->getQuerySettings();
            $querySettings->setRespectStoragePage(FALSE);
            $this->itemRepository->setDefaultQuerySettings($querySettings);

            // do your stuff here
            $source = 'foo';
            $rendered = 'bar';


            // then store it

            // this seems to be only necessary if we don't have an existing item yet
            // but as we don't know that here, we have to do it
            $item = $this->objectManager->get('STUBR\Therapiestellen\Domain\Model\Item');

            // find all existing items
            $all = $this->itemRepository->findAll();

            // if we have an item already, take the first (and only one)
            if(count($all) > 0){
                $item = $all->getFirst();
            }

            // set / update properties
            $item->setSource($source);
            $item->setRendered($r); 
            $item->setPid($storagePid);

            // either update or add it
            if(count($all) > 0){
                $this->itemRepository->update($item);
            }
            else {
                $this->itemRepository->add($item);
            }

            // persist it
            $this->persistenceManager->persistAll();
        }
}
?>

在EXT:ext_localconf.php中,添加命令controller:

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'NAMESPACE\\Myextension\\Controller\\ImportCommandController';

在计划程序中配置:

enter image description here

基本上就是这样!