Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Provide rules to migrate EXT:vhs viewhelpers #3424

Merged
merged 8 commits into from
Feb 5, 2024
23 changes: 23 additions & 0 deletions config/replace-vhs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs\ReplaceExtensionPathRelativeFluidRector;
use Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs\ReplaceFormatJsonEncodeFluidRector;
use Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs\ReplaceLFluidRector;
use Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs\ReplaceMediaImageFluidRector;
use Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs\ReplaceOrFluidRector;
use Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs\ReplaceUriImageFluidRector;
use Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs\ReplaceVariableSetFluidRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/config.php');
$rectorConfig->rule(ReplaceExtensionPathRelativeFluidRector::class);
$rectorConfig->rule(ReplaceFormatJsonEncodeFluidRector::class);
$rectorConfig->rule(ReplaceLFluidRector::class);
$rectorConfig->rule(ReplaceMediaImageFluidRector::class);
$rectorConfig->rule(ReplaceOrFluidRector::class);
$rectorConfig->rule(ReplaceUriImageFluidRector::class);
$rectorConfig->rule(ReplaceVariableSetFluidRector::class);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs;

use Nette\Utils\Strings;
use Rector\Core\Console\Output\RectorOutputStyle;
use Rector\Core\ValueObject\Application\File;
use Ssch\TYPO3Rector\Contract\FileProcessor\Fluid\Rector\FluidRectorInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

final class ReplaceExtensionPathRelativeFluidRector implements FluidRectorInterface
{
/**
* @var string
*/
private const PATTERN_INLINE = '#{(v|vhs):extension\.path\.relative\(extensionName:(\s?)["\']([a-z0-9_]+)["\']\)}Resources\/Public\/(\S+)\.([a-z0-9]{2,4})#ims';

/**
* @var string
*/
private const PATTERN_LEFTOVERS = '#(v|vhs):(extension\.path\.relative)#ims';

/**
* @readonly
*/
private RectorOutputStyle $rectorOutputStyle;

public function __construct(RectorOutputStyle $rectorOutputStyle)
{
$this->rectorOutputStyle = $rectorOutputStyle;
}

public function transform(File $file): void
{
$content = $file->getFileContent();

$content = Strings::replace(
$content,
self::PATTERN_INLINE,
'{f:uri.resource(extensionName:\'\3\',path:\'\4.\5\')}'
);

if (Strings::matchAll($content, self::PATTERN_LEFTOVERS)) {
$this->rectorOutputStyle->warning('There\'s occurrences of v:extension.path.relative that couldn\'t be migrated automatically. Migrate them manually!');
}

$file->changeFileContent($content);
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Use <f:uri.resource> instead of <v:extension.path.relative>', [
new CodeSample(
<<<'CODE_SAMPLE'
{v:extension.path.relative(extensionName:'my_extension')}Resources/Public/Css/style.css
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
{f:uri.resource(extensionName:'my_extension',path:'Css/style.css')}
CODE_SAMPLE
),
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs;

use Nette\Utils\Strings;
use Rector\Core\ValueObject\Application\File;
use Ssch\TYPO3Rector\Contract\FileProcessor\Fluid\Rector\FluidRectorInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

final class ReplaceFormatJsonEncodeFluidRector implements FluidRectorInterface
{
/**
* @var string
*/
private const PATTERN = '#(v|vhs):format.json.encode#imsU';

/**
* @var string
*/
private const REPLACEMENT = 'f:format.json';

public function transform(File $file): void
{
$content = $file->getFileContent();

$content = Strings::replace($content, self::PATTERN, self::REPLACEMENT);

$file->changeFileContent($content);
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Use <f:format.json> instead of <v:format.json.encode>', [
new CodeSample(
<<<'CODE_SAMPLE'
{someArray -> v:format.json.encode()}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
{someArray -> f:format.json()}
CODE_SAMPLE
),
]);
}
}
52 changes: 52 additions & 0 deletions src/FileProcessor/Fluid/Rector/vhs/ReplaceLFluidRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs;

use Nette\Utils\Strings;
use Rector\Core\ValueObject\Application\File;
use Ssch\TYPO3Rector\Contract\FileProcessor\Fluid\Rector\FluidRectorInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

final class ReplaceLFluidRector implements FluidRectorInterface
{
/**
* @var string
*/
private const PATTERN = '#(v|vhs):l([\( ])#imsU';

/**
* @var string
*/
private const REPLACEMENT = 'f:translate$2';

public function transform(File $file): void
{
$content = $file->getFileContent();

$content = Strings::replace($content, self::PATTERN, self::REPLACEMENT);

$file->changeFileContent($content);
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Use <f:translate> instead of <v:l>', [
new CodeSample(
<<<'CODE_SAMPLE'
<v:l key="my-key" extensionName="my_extension" />
<vhs:l key="my-other-key" />
<v:loop ...>
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
<f:translate key="my-key" extensionName="my_extension" />
<f:translate key="my-other-key" />
<v:loop ...>
CODE_SAMPLE
),
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs;

use Nette\Utils\Strings;
use Rector\Core\ValueObject\Application\File;
use Ssch\TYPO3Rector\Contract\FileProcessor\Fluid\Rector\FluidRectorInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

final class ReplaceMediaImageFluidRector implements FluidRectorInterface
{
/**
* @var string
*/
private const PATTERN = '#(v|vhs):media.image([\( ])#imsU';

/**
* @var string
*/
private const REPLACEMENT = 'f:image$2';

public function transform(File $file): void
{
$content = $file->getFileContent();

// TODO 1: handle 'relative' attribute -> transform to inverted 'absolute'
// TODO 2: handle maxW attribute -> rename to maxWidth
// TODO 3: handle maxH attribute -> rename to maxHeight
$content = Strings::replace($content, self::PATTERN, self::REPLACEMENT);

$file->changeFileContent($content);
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Use <f:image> instead of <v:media.image>', [
new CodeSample(
<<<'CODE_SAMPLE'
<v:media.image src="{image.uid}" treatIdAsReference="true" />
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
<f:image src="{image.uid}" treatIdAsReference="true" />
CODE_SAMPLE
),
]);
}
}
50 changes: 50 additions & 0 deletions src/FileProcessor/Fluid/Rector/vhs/ReplaceOrFluidRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs;

use Nette\Utils\Strings;
use Rector\Core\ValueObject\Application\File;
use Ssch\TYPO3Rector\Contract\FileProcessor\Fluid\Rector\FluidRectorInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

final class ReplaceOrFluidRector implements FluidRectorInterface
{
public function transform(File $file): void
{
$content = $file->getFileContent();

$content = Strings::replace(
$content,
'#-> (v|vhs):or\(alternative:(\s?)([^),]+)\)#ims',
'?: $3'
);

$content = Strings::replace(
$content,
'#(v|vhs):or\(content:(\s?)([^),]+),(\s?)alternative:(\s?)([^),]+)\)#ims',
'$3 ?: $6'
);

$file->changeFileContent($content);
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Use <f:or> instead of <v:or>', [
new CodeSample(
<<<'CODE_SAMPLE'
{someVariable -> v:or(alternative: 'Fallback text')}
{v:or(content: someVariable, alternative: 'Fallback text')}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
{someVariable ?: 'Fallback text'}
{someVariable ?: 'Fallback text'}
CODE_SAMPLE
),
]);
}
}
57 changes: 57 additions & 0 deletions src/FileProcessor/Fluid/Rector/vhs/ReplaceUriImageFluidRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\FileProcessor\Fluid\Rector\vhs;

use Nette\Utils\Strings;
use Rector\Core\ValueObject\Application\File;
use Ssch\TYPO3Rector\Contract\FileProcessor\Fluid\Rector\FluidRectorInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

final class ReplaceUriImageFluidRector implements FluidRectorInterface
{
/**
* @var string
*/
private const PATTERN = '#(v|vhs):uri.image#imsU';

/**
* @var string
*/
private const REPLACEMENT = 'f:uri.image';

public function transform(File $file): void
{
$content = $file->getFileContent();

// TODO 1: handle 'relative' attribute -> transform to inverted 'absolute'
// TODO 2: handle maxW attribute -> rename to maxWidth
// TODO 3: handle maxH attribute -> rename to maxHeight
$content = Strings::replace($content, self::PATTERN, self::REPLACEMENT);

$file->changeFileContent($content);
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Use <f:uri.image> instead of <v:uri.image>', [
new CodeSample(
<<<'CODE_SAMPLE'
{v:uri.image(src:image.uid, treatIdAsReference: 1)}
{v:uri.image(src:image.uid, treatIdAsReference: 1, relative: 1)}
{v:uri.image(src:image.uid, treatIdAsReference: 1, relative: 0)}
{v:uri.image(src:image.uid, treatIdAsReference: 1, maxW: 250, maxH: 250)}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
{f:uri.image(src:image.uid, treatIdAsReference: 1)}
{f:uri.image(src:image.uid, treatIdAsReference: 1)}
{f:uri.image(src:image.uid, treatIdAsReference: 1, absolute: 1)}
{f:uri.image(src:image.uid, treatIdAsReference: 1, maxWidth: 250, maxHeight: 250)}
CODE_SAMPLE
),
]);
}
}
Loading