1

我的 TCA 中有slug字段,通常它可以工作,当通过 Backend > List 模块添加时,即使我不输入任何值,uniqueeval 也会确保 slug 是唯一的,所以当我创建许多具有相同名称的行时Foo TYPO3 后端将确保它将解析为独特的 slug,如foo, foo-1,foo-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'
        ],
    ],
],

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');
}

当然 slug 是音符组。

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

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

4

3 回答 3

9

除了 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);

}

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

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

    return $query->execute(true)[0];
}

请注意,在执行上述代码之前需要保留记录。

参考:

于 2020-08-07T15:59:47.450 回答
3

根据 Elias 和 Jonas 的回答,我创建了一个可以简化事情的类,尤其是当您有更多模型要处理时

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

<?php
namespace VENDOR\Sitepackage\Utility; // <- to be replaced with your namespace

use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\DataHandling\Model\RecordStateFactory;
use TYPO3\CMS\Core\DataHandling\SlugHelper;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/***
 *
 * This file is part of the "Sitepackage" Extension for TYPO3 CMS.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 *  (c) 2020 Marcus Biesioroff <biesior@gmail.com>
 *  Concept by:  Elias Häußler
 *               Jonas Eberle
 *
 ***/
class SlugUtility
{
    /**
     * @param int    $uid UID of record saved in DB
     * @param string $tableName Name of the table to lookup for uniques
     * @param string $slugFieldName Name of the slug field
     *
     * @return string Resolved unique slug
     * @throws \TYPO3\CMS\Core\Exception\SiteNotFoundException
     */
    public static function generateUniqueSlug(int $uid, string $tableName, string $slugFieldName): string
    {

        /** @var Connection $connection */
        $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName);
        $queryBuilder = $connection->createQueryBuilder();

        $record = $queryBuilder
            ->select('*')
            ->from($tableName)
            ->where('uid=:uid')
            ->setParameter(':uid', $uid)
            ->execute()
            ->fetch();
        if (!$record) return false;

//      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);
        }
        return $slug;
    }
}

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

use VENDOR\Sitepackage\Utility\SlugUtility;
use \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;

...

$pageSlug = SlugUtility::generateUniqueSlug(
    5,        // int     $uid            UID of record saved in DB
    'pages',  // string  $tableName      Name of the table to lookup for uniques
    'slug'    // string  $slugFieldName  Name of the slug field
)

// or

$uniqueSlug = SlugUtility::generateUniqueSlug(
    123,
    'tx_garage_domain_model_car',
    'slug'
);

// or according to the original question, 
// if you created new model object with Extbase, 
// persist it, create unique slug with SlugUtility 
// set the slug property to the created model object and finally update

public function createAction(Car $newCar)
{
    $this->carRepository->add($newCar);
    GeneralUtility::makeInstance(PersistenceManager::class)->persistAll();
    $uniqueSlug = SlugUtility::generateUniqueSlug(
        $newCar->getUid(),
        'tx_garage_domain_model_car',
        'slug'
    );
    if($uniqueSlug) {
        $newCar->setSlug($uniqueSlug);
        $this->carRepository->update($newCar);
    }
    $this->redirect('list');
}

// no need for second call to persistAll() 
// as Extbase will call it at action's finalizing.

// etc.
于 2020-08-08T01:24:56.177 回答
2

可以SlugHelper直接使用。对于该用例,API 显然不是很流畅,但它可以工作......

$this->carRepository->add($newCar);

// probably you need to persist first - I am not sure if this is really necessary
$this->objectManager()->get(
  \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class
)->persistAll();

$table = 'tx_garage_domain_model_car';
$field = 'slug';

// a stripped down record with just the necessary fields is enough
$record = ['name' => $newCar->getName()];
$pid = $this->settings->persistence->... 

$slugHelper = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
  \TYPO3\CMS\Core\DataHandling\SlugHelper::class,
  $table,
  $field,
  $GLOBALS['TCA'][$table]['columns'][$field]['config']
);

$newCar->slug = $slugHelper->generate($record, $pid);
于 2020-08-07T15:49:28.420 回答