If the generated slugs are not quite correct after a TYPO3 update and have to be recreated, this can be done easily using a command, for example. But there are also other applications for creating slugs, such as creating data records in the frontend, which then also require a valid entry in table.path_segment at the end.
CreateSlug.php as an example service class for generating a new and unique slug value. In the example, the table name is hidden behind Event::TABLE_NAME:
<?php
declare(strict_types = 1);
namespace UniKn\UknCalendarize\Service;
use TYPO3\CMS\Core\DataHandling\Model\RecordState;
use TYPO3\CMS\Core\DataHandling\Model\RecordStateFactory;
use TYPO3\CMS\Core\DataHandling\SlugHelper;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use UniKn\UknCalendarize\Domain\Model\Event;
use UniKn\UknCalendarize\Utility\DatabaseUtility;
use UniKn\UknCalendarize\Utility\TcaUtility;
/**
* Class CreateSlug
*/
class CreateSlug
{
const SLUG_FIELDNAME = 'slug';
/**
* @param array $row tx_extension_domain_model_anything.*
* @param string $tableName tx_extension_domain_model_anything
* @return void
* @throws SiteNotFoundException
*/
public function recreateSlug(array $row, string $tableName): void
{
$slugHelper = GeneralUtility::makeInstance(
SlugHelper::class,
$tableName,
self::SLUG_FIELDNAME,
TcaUtility::getTcaOfField(self::SLUG_FIELDNAME, $tableName)['config']
);
$slug = $slugHelper->generate($row, $row['pid']);
$slugValue = $slugHelper->buildSlugForUniqueInSite($slug, $this->getRecordState($row, $tableName));
$this->persistSlug($tableName, $slugValue);
}
/**
* @param array $row tx_extension_domain_model_anything.*
* @param string $tableName tx_extension_domain_model_anything
* @return RecordState
*/
protected function getRecordState(array $row, string $tableName): RecordState
{
return GeneralUtility::makeInstance(RecordStateFactory::class, $tableName)
->fromArray($row);
}
/**
* @param array $row tx_extension_domain_model_anything.*
* @param string $tableName tx_extension_domain_model_anything
* @param string $slugValue
* @return void
*/
protected function persistSlug(array $row, string $tableName, string $slugValue)
{
$queryBuilder = DatabaseUtility::getQueryBuilderForTable($tableName);
$queryBuilder
->update($tableName)
->where('uid=' . (int)$row['uid'])
->set(self::SLUG_FIELDNAME, $slugValue)
->execute();
}
}
The associated DatabaseUtility.php file could look like this:
<?php
declare(strict_types=1);
namespace UniKn\UknCalendarize\Utility;
use Doctrine\DBAL\Driver\Exception as ExceptionDbalDriver;
use Doctrine\DBAL\Exception as ExceptionDbal;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class DatabaseUtility
*/
class DatabaseUtility
{
/**
* Cache existing fields
*
* @var array
*/
protected static array $fieldsExisting = [];
/**
* @param string $fieldName
* @param string $tableName
* @return bool
* @throws ExceptionDbal
* @throws ExceptionDbalDriver
*/
public static function isFieldExistingInTable(string $fieldName, string $tableName): bool
{
$found = false;
if (isset(self::$fieldsExisting[$tableName][$fieldName]) === false) {
$connection = self::getConnectionForTable($tableName);
$queryResult = $connection->executeQuery('describe ' . $tableName . ';')->fetchAllAssociative();
foreach ($queryResult as $fieldProperties) {
if ($fieldProperties['Field'] === $fieldName) {
$found = true;
break;
}
}
self::$fieldsExisting[$tableName][$fieldName] = $found;
} else {
$found = self::$fieldsExisting[$tableName][$fieldName];
}
return $found;
}
/**
* @param string $tableName
* @param bool $removeRestrictions
* @return QueryBuilder
*/
public static function getQueryBuilderForTable(string $tableName, bool $removeRestrictions = false): QueryBuilder
{
/** @var QueryBuilder $queryBuilder */
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
if ($removeRestrictions === true) {
$queryBuilder->getRestrictions()->removeAll();
}
return $queryBuilder;
}
/**
* @param string $tableName
* @return Connection
*/
public static function getConnectionForTable(string $tableName): Connection
{
return GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName);
}
}
Last but not least a TcaUtility.php class:
<?php
declare(strict_types = 1);
namespace UniKn\UknCalendarize\Utility;
/**
* Class TcaUtility
*/
class TcaUtility
{
/**
* @param string $fieldName
* @param string $tableName
* @return array
*/
public static function getTcaOfField(string $fieldName, string $tableName): array
{
if (empty($GLOBALS['TCA'][$tableName]['columns'][$fieldName])) {
throw new \LogicException('No TCA to field ' . $fieldName . ' and table ' . $tableName, 1570026984);
}
return (array)$GLOBALS['TCA'][$tableName]['columns'][$fieldName];
}
}