TYPO3/Extbase 如何在创建操作中创建独特的 slug?

bie*_*ior 0 frontend typo3 slug extbase typo3-10.x

slug我的 TCA 中有字段,通常它可以工作,当通过后端> 列表模块添加时,即使我不会输入任何值,uniqueeval 也确保 slug 是唯一的,因此当我创建许多具有相同名称的行时TYPO3后台将enshure,这将解决以独特的蛞蝓一样foofoo-1foo-2等荣誉!:

'slug'       => [
    'exclude'     => true,
    'label'       => 'Slug',
    'displayCond' => 'VERSION:IS:false',
    'config'      => [
        'type'              => 'slug',
        'generatorOptions'  => [
            'fields'         => ['name'],
            'fieldSeparator' => '/',
            'replacements'   => [
                '/' => '',
            ],
        ],
        'fallbackCharacter' => '-',
        'eval'              => 'unique',
        'default'           => '',
        'appearance'        => [
            'prefix' => \BIESIOR\Garage\UserFunctions\SlugPrefix::class . '->getPrefix'
        ],
    ],
],
Run Code Online (Sandbox Code Playgroud)

但是,当从我的表单中的new/create操作(如您所见,来自 extension_builder 的典型 Extbase CRUD)创建新对象时,例如:

public function createAction(Car $newCar)
{
    $this->addFlashMessage(
        'The object was created. Please be aware that this action is publicly accessible unless you implement an access check. See https://docs.typo3.org/typo3cms/extensions/extension_builder/User/Index.html', 
        '', 
        \TYPO3\CMS\Core\Messaging\AbstractMessage::WARNING);
    $this->carRepository->add($newCar);
    $this->redirect('list');
}
Run Code Online (Sandbox Code Playgroud)

当然 slug 是笔记集。

我的第一个想法是复制TCA type='slug'的逻辑,并使用一些自己的 JS、AJAX 和 PHP 添加此功能,但这听起来像是超载和耗时。尤其是我根本不希望用户关心 slug 部分。是否有任何简单的 API 可用于查找给定表的唯一 slug,可用于自定义操作?

注意这个问题不是关于如何用 JS 处理它,这只是概念。我想完全跳过 FE 用户的这一部分,他不需要知道 slug 是什么。就在创建一个新对象的过程中,我想获得独特的价值foo-123

小智 7

除了 Jonas Eberles 的回答之外,这里还有另一个例子,它也尊重evalslug 字段的配置(可以是uniqueInSiteuniqueInPid或者只是unique)。

use TYPO3\CMS\Core\DataHandling\Model\RecordStateFactory;
use TYPO3\CMS\Core\DataHandling\SlugHelper;
use TYPO3\CMS\Core\Utility\GeneralUtility;

...

public function createAction(Car $newCar)
{
    $this->carRepository->add($newCar);
    GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class)->persistAll();
    $record = $this->carRepository->findByUidAssoc($newCar->getUid())[0];

    $tableName = 'tx_garage_domain_model_car';
    $slugFieldName = 'slug';

//      Get field configuration
    $fieldConfig = $GLOBALS['TCA'][$tableName]['columns'][$slugFieldName]['config'];
    $evalInfo = GeneralUtility::trimExplode(',', $fieldConfig['eval'], true);

//      Initialize Slug helper
    /** @var SlugHelper $slugHelper */
    $slugHelper = GeneralUtility::makeInstance(
        SlugHelper::class,
        $tableName,
        $slugFieldName,
        $fieldConfig
    );

//      Generate slug

    $slug = $slugHelper->generate($record, $record['pid']);
    $state = RecordStateFactory::forName($tableName)
        ->fromArray($record, $record['pid'], $record['uid']);

//      Build slug depending on eval configuration
    if (in_array('uniqueInSite', $evalInfo)) {
        $slug = $slugHelper->buildSlugForUniqueInSite($slug, $state);
    } else if (in_array('uniqueInPid', $evalInfo)) {
        $slug = $slugHelper->buildSlugForUniqueInPid($slug, $state);
    } else if (in_array('unique', $evalInfo)) {
        $slug = $slugHelper->buildSlugForUniqueInTable($slug, $state);
    }
    $newCar->setSlug($slug);
    $this->carRepository->update($newCar);

}
Run Code Online (Sandbox Code Playgroud)

在存储库中使用自定义查找器来获取 assoc 数组而不是$racord参数的映射对象

public function findByUidAssoc($uid)
{
    $query = $this->createQuery();
    $query->matching(
        $query->equals('uid', $uid)
    );

    return $query->execute(true)[0];
}
Run Code Online (Sandbox Code Playgroud)

请注意,在执行上述代码之前,需要将记录持久化。

参考:


bie*_*ior 5

根据 Elias 和 Jonas 的回答,我创建了一个类来简化事情,特别是当你有更多模型需要处理时

\n

typo3conf/ext/sitepackage/Classes/Utility/SlugUtility.php

\n
<?php\nnamespace VENDOR\\Sitepackage\\Utility; // <- to be replaced with your namespace\n\nuse TYPO3\\CMS\\Core\\Database\\Connection;\nuse TYPO3\\CMS\\Core\\Database\\ConnectionPool;\nuse TYPO3\\CMS\\Core\\DataHandling\\Model\\RecordStateFactory;\nuse TYPO3\\CMS\\Core\\DataHandling\\SlugHelper;\nuse TYPO3\\CMS\\Core\\Utility\\GeneralUtility;\n/***\n *\n * This file is part of the "Sitepackage" Extension for TYPO3 CMS.\n *\n * For the full copyright and license information, please read the\n * LICENSE.txt file that was distributed with this source code.\n *\n *  (c) 2020 Marcus Biesioroff <biesior@gmail.com>\n *  Concept by:  Elias H\xc3\xa4u\xc3\x9fler\n *               Jonas Eberle\n *\n ***/\nclass SlugUtility\n{\n    /**\n     * @param int    $uid UID of record saved in DB\n     * @param string $tableName Name of the table to lookup for uniques\n     * @param string $slugFieldName Name of the slug field\n     *\n     * @return string Resolved unique slug\n     * @throws \\TYPO3\\CMS\\Core\\Exception\\SiteNotFoundException\n     */\n    public static function generateUniqueSlug(int $uid, string $tableName, string $slugFieldName): string\n    {\n\n        /** @var Connection $connection */\n        $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName);\n        $queryBuilder = $connection->createQueryBuilder();\n\n        $record = $queryBuilder\n            ->select(\'*\')\n            ->from($tableName)\n            ->where(\'uid=:uid\')\n            ->setParameter(\':uid\', $uid)\n            ->execute()\n            ->fetch();\n        if (!$record) return false;\n\n//      Get field configuration\n        $fieldConfig = $GLOBALS[\'TCA\'][$tableName][\'columns\'][$slugFieldName][\'config\'];\n        $evalInfo = GeneralUtility::trimExplode(\',\', $fieldConfig[\'eval\'], true);\n\n//      Initialize Slug helper\n        /** @var SlugHelper $slugHelper */\n        $slugHelper = GeneralUtility::makeInstance(\n            SlugHelper::class,\n            $tableName,\n            $slugFieldName,\n            $fieldConfig\n        );\n//      Generate slug\n        $slug = $slugHelper->generate($record, $record[\'pid\']);\n        $state = RecordStateFactory::forName($tableName)\n            ->fromArray($record, $record[\'pid\'], $record[\'uid\']);\n\n//      Build slug depending on eval configuration\n        if (in_array(\'uniqueInSite\', $evalInfo)) {\n            $slug = $slugHelper->buildSlugForUniqueInSite($slug, $state);\n        } else if (in_array(\'uniqueInPid\', $evalInfo)) {\n            $slug = $slugHelper->buildSlugForUniqueInPid($slug, $state);\n        } else if (in_array(\'unique\', $evalInfo)) {\n            $slug = $slugHelper->buildSlugForUniqueInTable($slug, $state);\n        }\n        return $slug;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在任何地方使用,例如控制器。调度程序任务、存储库等。请记住,记录应该在之前保存(可以由 Extbase 创建,或者仅使用普通 SQL 创建),只需已创建uid并且是有效的 TYPO3 记录即可。

\n
use VENDOR\\Sitepackage\\Utility\\SlugUtility;\nuse \\TYPO3\\CMS\\Extbase\\Persistence\\Generic\\PersistenceManager;\n\n...\n\n$pageSlug = SlugUtility::generateUniqueSlug(\n    5,        // int     $uid            UID of record saved in DB\n    \'pages\',  // string  $tableName      Name of the table to lookup for uniques\n    \'slug\'    // string  $slugFieldName  Name of the slug field\n)\n\n// or\n\n$uniqueSlug = SlugUtility::generateUniqueSlug(\n    123,\n    \'tx_garage_domain_model_car\',\n    \'slug\'\n);\n\n// or according to the original question, \n// if you created new model object with Extbase, \n// persist it, create unique slug with SlugUtility \n// set the slug property to the created model object and finally update\n\npublic function createAction(Car $newCar)\n{\n    $this->carRepository->add($newCar);\n    GeneralUtility::makeInstance(PersistenceManager::class)->persistAll();\n    $uniqueSlug = SlugUtility::generateUniqueSlug(\n        $newCar->getUid(),\n        \'tx_garage_domain_model_car\',\n        \'slug\'\n    );\n    if($uniqueSlug) {\n        $newCar->setSlug($uniqueSlug);\n        $this->carRepository->update($newCar);\n    }\n    $this->redirect(\'list\');\n}\n\n// no need for second call to persistAll() \n// as Extbase will call it at action\'s finalizing.\n\n// etc.\n
Run Code Online (Sandbox Code Playgroud)\n