Skip to content

Commit

Permalink
[FEATURE] New TCA type "datetime" (sabbelasichon#3556)
Browse files Browse the repository at this point in the history
  • Loading branch information
m11r86 committed Oct 22, 2023
1 parent 4227408 commit 7eaa909
Show file tree
Hide file tree
Showing 5 changed files with 409 additions and 0 deletions.
2 changes: 2 additions & 0 deletions config/v12/tca-120.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Rector\Config\RectorConfig;
use Ssch\TYPO3Rector\Rector\v12\v0\tca\MigrateColsToSizeForTcaTypeNoneRector;
use Ssch\TYPO3Rector\Rector\v12\v0\tca\MigrateInputDateTimeRector;
use Ssch\TYPO3Rector\Rector\v12\v0\tca\MigrateInternalTypeRector;
use Ssch\TYPO3Rector\Rector\v12\v0\tca\MigrateNullFlagRector;
use Ssch\TYPO3Rector\Rector\v12\v0\tca\MigrateRequiredFlagRector;
Expand All @@ -15,6 +16,7 @@
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/../config.php');
$rectorConfig->rule(MigrateColsToSizeForTcaTypeNoneRector::class);
$rectorConfig->rule(MigrateInputDateTimeRector::class);
$rectorConfig->rule(MigrateInternalTypeRector::class);
$rectorConfig->rule(MigrateNullFlagRector::class);
$rectorConfig->rule(MigrateRequiredFlagRector::class);
Expand Down
199 changes: 199 additions & 0 deletions src/Rector/v12/v0/tca/MigrateInputDateTimeRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\Rector\v12\v0\tca;

use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use Ssch\TYPO3Rector\Helper\ArrayUtility;
use Ssch\TYPO3Rector\Helper\TcaHelperTrait;
use Ssch\TYPO3Rector\Rector\Tca\AbstractTcaRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use TYPO3\CMS\Core\Utility\MathUtility;

/**
* @changelog https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/12.0/Feature-97232-NewTCATypeDatetime.html
* @see \Ssch\TYPO3Rector\Tests\Rector\v12\v0\tca\MigrateInputDateTimeRector\MigrateInputDateTimeRectorTest
*/
final class MigrateInputDateTimeRector extends AbstractTcaRector
{
use TcaHelperTrait;

/**
* @var string
*/
private const INPUT_DATE_TIME = 'inputDateTime';

/**
* @var string[]
*/
private const DATETIME_TYPES = ['date', 'datetime', 'time'];

/**
* @var array<string, array<string, string>>
*/
private const DATETIME_EMPTY_VALUES = [
'date' => [
'empty' => '0000-00-00',
],
'datetime' => [
'empty' => '0000-00-00 00:00:00',
],
'time' => [
'empty' => '00:00:00',
],
];

/**
* @codeCoverageIgnore
*/
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Migrate renderType inputDateTime to new TCA type datetime', [new CodeSample(
<<<'CODE_SAMPLE'
'a_datetime_field' => [
'label' => 'Datetime field',
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'required' => true,
'size' => 20,
'max' => 1024,
'eval' => 'date,int',
'default' => 0,
],
],
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
'a_datetime_field' => [
'label' => 'Datetime field',
'config' => [
'type' => 'datetime',
'format' => 'date',
'required' => true,
'size' => 20,
'default' => 0,
]
]
CODE_SAMPLE
)]);
}

protected function refactorColumn(Expr $columnName, Expr $columnTca): void
{
$configArray = $this->extractSubArrayByKey($columnTca, self::CONFIG);
if (! $configArray instanceof Array_) {
return;
}

// Early return in case column is not of type=input with renderType=inputDateTime
if (! $this->isConfigType($configArray, 'input')) {
return;
}

if (! $this->configIsOfRenderType($configArray, self::INPUT_DATE_TIME)) {
return;
}

// Set the TCA type to "datetime"
$typeArrayItem = $this->extractArrayItemByKey($configArray, 'type');
if (! $typeArrayItem instanceof ArrayItem) {
return;
}

$typeArrayItem->value = new String_('datetime');

// Remove 'renderType' => 'inputDateTime',
$renderTypeArrayItem = $this->extractArrayItemByKey($configArray, 'renderType');

if (! $renderTypeArrayItem instanceof ArrayItem) {
return;
}

$renderTypeValue = $this->valueResolver->getValue($renderTypeArrayItem->value);

if (! is_string($renderTypeValue)) {
return;
}

$this->removeNode($renderTypeArrayItem);

// Remove 'max' config
$maxArrayItem = $this->extractArrayItemByKey($configArray, 'max');
if ($maxArrayItem instanceof ArrayItem) {
$this->removeNode($maxArrayItem);
}

$evalList = [];
$evalArrayItem = $this->extractArrayItemByKey($configArray, 'eval');
if ($evalArrayItem instanceof ArrayItem) {
$evalString = $this->valueResolver->getValue($evalArrayItem->value);

if (! is_string($evalString)) {
return;
}

$evalList = ArrayUtility::trimExplode(',', $evalString, true);

// Remove 'eval' config
$this->removeNode($evalArrayItem);
}

// Remove format config, if set
$formatArrayItem = $this->extractArrayItemByKey($configArray, 'format');
if ($formatArrayItem instanceof ArrayItem) {
$this->removeNode($formatArrayItem);
}

// Set the "format" based on "eval"
// If no 'format' config is set it will fall back to 'datetime'
if ($evalList !== []) {
if (in_array('date', $evalList, true)) {
$configArray->items[] = new ArrayItem(new String_('date'), new String_('format'));
} elseif (in_array('time', $evalList, true)) {
$configArray->items[] = new ArrayItem(new String_('time'), new String_('format'));
} elseif (in_array('timesec', $evalList, true)) {
$configArray->items[] = new ArrayItem(new String_('timesec'), new String_('format'));
}
}

// Removes option [config][default], if the default is the native "empty" value

$defaultArrayItem = $this->extractArrayItemByKey($configArray, 'default');

if ($defaultArrayItem instanceof ArrayItem) {
$dbTypeValue = null;
$defaultValue = $this->valueResolver->getValue($defaultArrayItem->value);
$dbTypeArrayItem = $this->extractArrayItemByKey($configArray, 'dbType');

if ($dbTypeArrayItem instanceof ArrayItem) {
$dbTypeValue = $this->valueResolver->getValue($dbTypeArrayItem->value);
}

if (in_array($dbTypeValue, self::DATETIME_TYPES, true)) {
if ($defaultValue === self::DATETIME_EMPTY_VALUES[$dbTypeValue]['empty']) {
$this->removeNode($defaultArrayItem);
}
} elseif (! is_int($defaultValue)) {
if ($defaultValue === '') {
// Always use int as default (string values are no longer supported for "datetime")
$defaultArrayItem->value = new LNumber(0);
} elseif (MathUtility::canBeInterpretedAsInteger($defaultValue)) {
// Cast default to int, in case it can be interpreted as integer
$defaultArrayItem->value = new LNumber((int) $defaultValue);
} else {
// Unset default in case it's a no longer supported string
$this->removeNode($defaultArrayItem);
}
}
}

$this->hasAstBeenChanged = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php

namespace Ssch\TYPO3Rector\Tests\Rector\v12\v0\tca\MigrateRequiredFlagRector\Fixture;

return [
'ctrl' => [],
'columns' => [
'a_date_field' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'required' => true,
'size' => 20,
'max' => 1024,
'eval' => 'date,int',
'default' => 0,
],
],
'a_datetime_field' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'datetime',
'size' => 20,
'required' => true,
],
],
'a_timesec_field' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'eval' => 'timesec',
],
],
'format_datetime' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'format' => 'datetime',
],
],
'default_string_zero' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'default' => '0',
],
],
'default_string_cast' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'default' => '9',
],
],
'default_empty' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'default' => '',
],
],
'default_empty_date' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'dbType' => 'date',
'default' => '0000-00-00',
],
],
'default_empty_datetime' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'dbType' => 'datetime',
'default' => '0000-00-00 00:00:00',
],
],
'default_empty_time' => [
'config' => [
'type' => 'input',
'renderType' => 'inputDateTime',
'dbType' => 'time',
'default' => '00:00:00',
],
],
],
];

?>
-----
<?php

namespace Ssch\TYPO3Rector\Tests\Rector\v12\v0\tca\MigrateRequiredFlagRector\Fixture;

return [
'ctrl' => [],
'columns' => [
'a_date_field' => [
'config' => [
'type' => 'datetime',
'required' => true,
'size' => 20,
'default' => 0,
'format' => 'date',
],
],
'a_datetime_field' => [
'config' => [
'type' => 'datetime',
'size' => 20,
'required' => true,
],
],
'a_timesec_field' => [
'config' => [
'type' => 'datetime',
'format' => 'timesec',
],
],
'format_datetime' => [
'config' => [
'type' => 'datetime',
],
],
'default_string_zero' => [
'config' => [
'type' => 'datetime',
'default' => 0,
],
],
'default_string_cast' => [
'config' => [
'type' => 'datetime',
'default' => 9,
],
],
'default_empty' => [
'config' => [
'type' => 'datetime',
'default' => 0,
],
],
'default_empty_date' => [
'config' => [
'type' => 'datetime',
'dbType' => 'date',
],
],
'default_empty_datetime' => [
'config' => [
'type' => 'datetime',
'dbType' => 'datetime',
],
],
'default_empty_time' => [
'config' => [
'type' => 'datetime',
'dbType' => 'time',
],
],
],
];

?>
Loading

0 comments on commit 7eaa909

Please sign in to comment.