Skip to content

Commit

Permalink
[FEATURE] MigratePasswordAndSaltedPasswordToPasswordTypeFlexFormRector
Browse files Browse the repository at this point in the history
Resolves: #3545
  • Loading branch information
simonschaufi committed Dec 28, 2023
1 parent c4796ce commit ee9669b
Show file tree
Hide file tree
Showing 19 changed files with 378 additions and 74 deletions.
2 changes: 2 additions & 0 deletions config/v12/flexform-120.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\MigrateEvalIntAndDouble2ToTypeNumberFlexFormRector;
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\MigrateInternalTypeFolderToTypeFolderFlexFormRector;
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\MigrateNullFlagFlexFormRector;
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\MigratePasswordAndSaltedPasswordToPasswordTypeFlexFormRector;
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\RemoveElementTceFormsRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/../config.php');
$rectorConfig->rule(MigrateEvalIntAndDouble2ToTypeNumberFlexFormRector::class);
$rectorConfig->rule(MigrateInternalTypeFolderToTypeFolderFlexFormRector::class);
$rectorConfig->rule(MigrateNullFlagFlexFormRector::class);
$rectorConfig->rule(MigratePasswordAndSaltedPasswordToPasswordTypeFlexFormRector::class);
$rectorConfig->rule(RemoveElementTceFormsRector::class);
};
20 changes: 20 additions & 0 deletions src/Helper/FlexFormHelperTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ private function hasKeyValuePair(DOMElement $configValueArray, string $configKey
return false;
}

private function removeChildElementFromDomElementByKey(DOMElement $configValueArray, string $configKey): bool
{
$arrayItemToRemove = $this->extractDomElementByKey($configValueArray, $configKey);
if ($arrayItemToRemove instanceof DOMElement && $arrayItemToRemove->parentNode instanceof DOMElement) {
$arrayItemToRemove->parentNode->removeChild($arrayItemToRemove);
return true;
}

return false;
}

private function isValue(string $element, string $value): bool
{
return $element === $value;
Expand All @@ -104,4 +115,13 @@ private function changeTagName(DOMDocument $domDocument, DOMElement $node, strin

$node->parentNode->replaceChild($newNode, $node);
}

private function changeTcaType(DOMDocument $domDocument, DOMElement $configElement, string $newType): void
{
$toChangeItem = $this->extractDomElementByKey($configElement, 'type');
if ($toChangeItem instanceof DOMElement) {
$toChangeItem->nodeValue = '';
$toChangeItem->appendChild($domDocument->createTextNode($newType));
}
}
}
9 changes: 9 additions & 0 deletions src/Helper/TcaHelperTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Return_;

trait TcaHelperTrait
Expand Down Expand Up @@ -137,6 +138,14 @@ protected function configIsOfRenderType(Array_ $configValueArray, string $expect
return $this->hasKeyValuePair($configValueArray, 'renderType', $expectedRenderType);
}

protected function changeTcaType(Array_ $configArray, string $type): void
{
$toChangeArrayItem = $this->extractArrayItemByKey($configArray, 'type');
if ($toChangeArrayItem instanceof ArrayItem) {
$toChangeArrayItem->value = new String_($type);
}
}

private function isInlineType(Array_ $columnItemConfigurationArray): bool
{
return $this->isConfigType($columnItemConfigurationArray, 'inline');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,11 @@ private function refactorColumn(DOMDocument $domDocument, ?DOMElement $configEle
}

$evalDomElement = $this->extractDomElementByKey($configElement, 'eval');

if (! $evalDomElement instanceof DOMElement) {
return;
}

$evalListValue = $evalDomElement->nodeValue;

if (! is_string($evalListValue)) {
return;
}
Expand Down Expand Up @@ -143,11 +141,7 @@ private function refactorColumn(DOMDocument $domDocument, ?DOMElement $configEle
$evalDomElement->parentNode->removeChild($evalDomElement);
}

$toChangeItem = $this->extractDomElementByKey($configElement, 'type');
if ($toChangeItem instanceof DOMElement) {
$toChangeItem->nodeValue = '';
$toChangeItem->appendChild($domDocument->createTextNode('number'));
}
$this->changeTcaType($domDocument, $configElement, 'number');

if (StringUtility::inList($evalListValue, self::DOUBLE2)) {
$configElement->appendChild($domDocument->createElement('format', 'decimal'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ private function refactorColumn(DOMDocument $domDocument, ?DOMElement $configEle
}

$internalTypeDomElement = $this->extractDomElementByKey($configElement, 'internal_type');

if (! $internalTypeDomElement instanceof DOMElement) {
return;
}
Expand All @@ -105,14 +104,8 @@ private function refactorColumn(DOMDocument $domDocument, ?DOMElement $configEle
$internalTypeDomElement->parentNode->removeChild($internalTypeDomElement);
}

$internalTypeValue = $internalTypeDomElement->nodeValue;

if ($internalTypeValue === 'folder') {
$toChangeItem = $this->extractDomElementByKey($configElement, 'type');
if ($toChangeItem instanceof DOMElement) {
$toChangeItem->nodeValue = '';
$toChangeItem->appendChild($domDocument->createTextNode('folder'));
}
if ($internalTypeDomElement->nodeValue === 'folder') {
$this->changeTcaType($domDocument, $configElement, 'folder');
}

$this->domDocumentHasBeenChanged = true;
Expand Down
7 changes: 2 additions & 5 deletions src/Rector/v12/v0/flexform/MigrateNullFlagFlexFormRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ private function refactorColumn(DOMDocument $domDocument, ?DOMElement $configEle
}

$evalListValue = $evalDomElement->nodeValue;

if (! is_string($evalListValue)) {
return;
}
Expand All @@ -132,12 +131,10 @@ private function refactorColumn(DOMDocument $domDocument, ?DOMElement $configEle
}

$nullableDomElement = $this->extractDomElementByKey($configElement, 'nullable');
if ($nullableDomElement instanceof DOMElement && $nullableDomElement->parentNode instanceof DOMElement) {
$nullableDomElement->parentNode->removeChild($nullableDomElement);
if (! $nullableDomElement instanceof DOMElement) {
$configElement->appendChild($domDocument->createElement('nullable', '1'));
}

$configElement->appendChild($domDocument->createElement('nullable', 'true'));

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

declare(strict_types=1);

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

use DOMDocument;
use DOMElement;
use DOMNodeList;
use DOMXPath;
use Ssch\TYPO3Rector\Contract\FileProcessor\FlexForms\Rector\FlexFormRectorInterface;
use Ssch\TYPO3Rector\Helper\ArrayUtility;
use Ssch\TYPO3Rector\Helper\FlexFormHelperTrait;
use Ssch\TYPO3Rector\Helper\StringUtility;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @changelog https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/12.0/Feature-97159-NewTCATypeLink.html
* @see \Ssch\TYPO3Rector\Tests\Rector\v12\v0\flexform\MigratePasswordAndSaltedPasswordToPasswordTypeFlexFormRector\MigratePasswordAndSaltedPasswordToPasswordTypeFlexFormRectorTest
*/
final class MigratePasswordAndSaltedPasswordToPasswordTypeFlexFormRector implements FlexFormRectorInterface
{
use FlexFormHelperTrait;

/**
* @var string
*/
private const PASSWORD = 'password';

/**
* @var string
*/
private const SALTED_PASSWORD = 'saltedPassword';

private bool $domDocumentHasBeenChanged = false;

public function transform(DOMDocument $domDocument): bool
{
$xpath = new DOMXPath($domDocument);

/** @var DOMNodeList<DOMElement> $elements */
$elements = $xpath->query('//config');

if ($elements->count() === 0) {
return false;
}

foreach ($elements as $element) {
$this->refactorColumn($domDocument, $element);
}

return $this->domDocumentHasBeenChanged;
}

/**
* @codeCoverageIgnore
*/
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Migrate password and salted password to password type', [new CodeSample(
<<<'CODE_SAMPLE'
<T3DataStructure>
<ROOT>
<sheetTitle>aTitle</sheetTitle>
<type>array</type>
<el>
<password_field>
<label>Password</label>
<config>
<type>input</type>
<eval>trim,password,saltedPassword</eval>
</config>
</password_field>
<another_password_field>
<label>Password</label>
<config>
<type>input</type>
<eval>trim,password</eval>
</config>
</another_password_field>
</el>
</ROOT>
</T3DataStructure>
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
<T3DataStructure>
<ROOT>
<sheetTitle>aTitle</sheetTitle>
<type>array</type>
<el>
<password_field>
<label>Password</label>
<config>
<type>password</type>
</config>
</password_field>
<another_password_field>
<label>Password</label>
<config>
<type>password</type>
<hashed>false</hashed>
</config>
</another_password_field>
</el>
</ROOT>
</T3DataStructure>
CODE_SAMPLE
)]);
}

private function refactorColumn(DOMDocument $domDocument, ?DOMElement $configElement): void
{
if (! $configElement instanceof DOMElement) {
return;
}

if (! $this->isConfigType($configElement, 'input')) {
return;
}

if (! $this->hasKey($configElement, 'eval')) {
return;
}

$evalDomElement = $this->extractDomElementByKey($configElement, 'eval');
if (! $evalDomElement instanceof DOMElement) {
return;
}

$evalListValue = $evalDomElement->nodeValue;
if (! is_string($evalListValue)) {
return;
}

if (! StringUtility::inList($evalListValue, self::PASSWORD)
&& ! StringUtility::inList($evalListValue, self::SALTED_PASSWORD)
) {
return;
}

// Set the TCA type to "password"
$this->changeTcaType($domDocument, $configElement, self::PASSWORD);

// Remove 'max' and 'search' config
$this->removeChildElementFromDomElementByKey($configElement, 'max');
$this->removeChildElementFromDomElementByKey($configElement, 'search');

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

// Disable password hashing, if eval=password is used standalone
if (in_array('password', $evalList, true) && ! in_array('saltedPassword', $evalList, true)) {
$configElement->appendChild($domDocument->createElement('hashed', '0'));
}

if (in_array('null', $evalList, true)) {
// Set "eval" to "null", since it's currently defined and the only allowed "eval" for type=password
$evalDomElement->nodeValue = '';
$evalDomElement->appendChild($domDocument->createTextNode('null'));
} elseif ($evalDomElement->parentNode instanceof DOMElement) {
// 'eval' is empty, remove whole configuration
$evalDomElement->parentNode->removeChild($evalDomElement);
}

$this->domDocumentHasBeenChanged = true;
}
}
2 changes: 0 additions & 2 deletions src/Rector/v12/v0/flexform/RemoveElementTceFormsRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,12 @@ public function transform(DOMDocument $domDocument): bool

// Find all elements with a <TCEforms> parent and move their children to the parent level
$tceformsElements = $xpath->query('//TCEforms');

if (! $tceformsElements instanceof DOMNodeList) {
return false;
}

foreach ($tceformsElements as $tceformsElement) {
$parent = $tceformsElement->parentNode;

if (! $parent instanceof DOMElement) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,11 @@ protected function refactorColumn(Expr $columnName, Expr $columnTca): void
}

$evalArrayItem = $this->extractArrayItemByKey($configArray, 'eval');

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

$evalListValue = $this->valueResolver->getValue($evalArrayItem->value);

if (! is_string($evalListValue)) {
return;
}
Expand All @@ -125,10 +123,7 @@ protected function refactorColumn(Expr $columnName, Expr $columnTca): void
$this->removeNode($evalArrayItem);
}

$toChangeArrayItem = $this->extractArrayItemByKey($configArray, 'type');
if ($toChangeArrayItem instanceof ArrayItem) {
$toChangeArrayItem->value = new String_('number');
}
$this->changeTcaType($configArray, 'number');

if (StringUtility::inList($evalListValue, self::DOUBLE2)) {
$configArray->items[] = new ArrayItem(new String_('decimal'), new String_('format'));
Expand Down
7 changes: 1 addition & 6 deletions src/Rector/v12/v0/tca/MigrateInputDateTimeRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,7 @@ protected function refactorColumn(Expr $columnName, Expr $columnTca): void
}

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

$typeArrayItem->value = new String_('datetime');
$this->changeTcaType($configArray, 'datetime');

// Remove 'renderType' => 'inputDateTime',
$renderTypeArrayItem = $this->extractArrayItemByKey($configArray, 'renderType');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Scalar\String_;
use Ssch\TYPO3Rector\Helper\TcaHelperTrait;
use Ssch\TYPO3Rector\Rector\Tca\AbstractTcaRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
Expand Down Expand Up @@ -67,10 +66,7 @@ protected function refactorColumn(Expr $columnName, Expr $columnTca): void
$this->removeNode($toRemoveArrayItem);
}

$toChangeArrayItem = $this->extractArrayItemByKey($configArray, 'type');
if ($toChangeArrayItem instanceof ArrayItem) {
$toChangeArrayItem->value = new String_('folder');
}
$this->changeTcaType($configArray, 'folder');

$this->hasAstBeenChanged = true;
}
Expand Down
Loading

0 comments on commit ee9669b

Please sign in to comment.