Skip to content

Commit

Permalink
Merge pull request #39 from neos/task/node-properties
Browse files Browse the repository at this point in the history
TASK: Refactor node properties
  • Loading branch information
ahaeslich authored Nov 5, 2023
2 parents be84b8b + 5783745 commit 255ab72
Show file tree
Hide file tree
Showing 14 changed files with 503 additions and 26 deletions.
73 changes: 47 additions & 26 deletions config/set/contentrepository-90.php

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions src/ContentRepository90/Rules/FusionNodeAutoCreatedRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Neos\Rector\ContentRepository90\Rules;

use Neos\Rector\Core\FusionProcessing\EelExpressionTransformer;
use Neos\Rector\Core\FusionProcessing\FusionRectorInterface;
use Neos\Rector\Utility\CodeSampleLoader;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

class FusionNodeAutoCreatedRector implements FusionRectorInterface
{

public function getRuleDefinition(): RuleDefinition
{
return CodeSampleLoader::fromFile('Fusion: Rewrite node.autoCreated to node.classification.tethered', __CLASS__);
}

public function refactorFileContent(string $fileContent): string
{
return EelExpressionTransformer::parse($fileContent)
->process(fn(string $eelExpression) => preg_replace(
'/(node|documentNode|site)\.autoCreated/',
'$1.classification.tethered',
$eelExpression
))
->addCommentsIfRegexMatches(
'/\.autoCreated/',
'// TODO 9.0 migration: Line %LINE: !! You very likely need to rewrite "VARIABLE.autoCreated" to "VARIABLE.classification.tethered". We did not auto-apply this migration because we cannot be sure whether the variable is a Node.'
)->getProcessedContent();
}
}
33 changes: 33 additions & 0 deletions src/ContentRepository90/Rules/FusionNodeContextPathRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Neos\Rector\ContentRepository90\Rules;

use Neos\Rector\Core\FusionProcessing\EelExpressionTransformer;
use Neos\Rector\Core\FusionProcessing\FusionRectorInterface;
use Neos\Rector\Utility\CodeSampleLoader;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

class FusionNodeContextPathRector implements FusionRectorInterface
{

public function getRuleDefinition(): RuleDefinition
{
return CodeSampleLoader::fromFile('Fusion: Rewrite node.contextPath to Neos.Node.serializedNodeAddress(node)', __CLASS__);
}

public function refactorFileContent(string $fileContent): string
{
return EelExpressionTransformer::parse($fileContent)
->process(fn(string $eelExpression) => preg_replace(
'/(node|documentNode|site)\.contextPath/',
'Neos.Node.serializedNodeAddress($1)',
$eelExpression
))
->addCommentsIfRegexMatches(
'/\.contextPath/',
'// TODO 9.0 migration: Line %LINE: !! You very likely need to rewrite "VARIABLE.contextPath" to "Neos.Node.serializedNodeAddress(VARIABLE)". We did not auto-apply this migration because we cannot be sure whether the variable is a Node.'
)->getProcessedContent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace Neos\Rector\Generic\Rules;

use Neos\Rector\Core\FusionProcessing\AfxParser\AfxParserException;
use Neos\Rector\Core\FusionProcessing\EelExpressionTransformer;
use Neos\Rector\Core\FusionProcessing\FusionParser\Exception\ParserException;
use Neos\Rector\Core\FusionProcessing\FusionRectorInterface;
use Neos\Rector\Core\FusionProcessing\Helper\RegexCommentTemplatePair;
use Neos\Rector\Utility\CodeSampleLoader;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Webmozart\Assert\Assert;
use Neos\Rector\Generic\ValueObject\FusionFlowQueryNodePropertyToWarningComment;

class FusionFlowQueryNodePropertyToWarningCommentRector implements FusionRectorInterface, ConfigurableRectorInterface
{

use AllTraits;

/** @var FusionFlowQueryNodePropertyToWarningComment[] */
private array $fusionFlowQueryNodePropertyToWarningComments = [];

public function getRuleDefinition(): RuleDefinition
{
return CodeSampleLoader::fromFile('Fusion: Adds a warning comment when the defined property is used within an FlowQuery "property()".', __CLASS__, [
new FusionFlowQueryNodePropertyToWarningComment('_autoCreated', 'Line %LINE: !! You very likely need to rewrite "q(VARIABLE).property("_autoCreated")" to "VARIABLE.classification.tethered". We did not auto-apply this migration because we cannot be sure whether the variable is a Node.')
]);
}

/**
* @throws ParserException
* @throws AfxParserException
*/
public function refactorFileContent(string $fileContent): string
{

$regexWarningMessagePairs = [];
foreach ($this->fusionFlowQueryNodePropertyToWarningComments as $flowQueryNodePropertyToWarningComment) {
$property = $flowQueryNodePropertyToWarningComment->property;
$regexWarningMessagePairs[] = new RegexCommentTemplatePair(
"/\.property\(('|\")$property('|\")\)/",
(string)self::todoCommentAttribute($flowQueryNodePropertyToWarningComment->warningMessage)
);

}

return EelExpressionTransformer::parse($fileContent)
->addCommentsIfRegexesMatch($regexWarningMessagePairs)
->getProcessedContent();

}

/**
* @param FusionFlowQueryNodePropertyToWarningComment[] $configuration
*/
public function configure(array $configuration): void
{
Assert::allIsAOf($configuration, FusionFlowQueryNodePropertyToWarningComment::class);
$this->fusionFlowQueryNodePropertyToWarningComments = $configuration;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Neos\Rector\Generic\ValueObject;

class FusionFlowQueryNodePropertyToWarningComment
{
public function __construct(
public readonly string $property,
public readonly string $warningMessage,
)
{
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
prototype(Neos.Fusion.Form:Checkbox) < prototype(Neos.Fusion.Form:Component.Field) {

renderer = Neos.Fusion:Component {

#
# pass down props
#
attributes = ${node.autoCreated || documentNode.autoCreated}

#
# the `checked` state is calculated outside the renderer to allow` overriding via `attributes`
#
checked = false
checked.@process.checkMultiValue = ${Array.indexOf(field.getCurrentMultivalueStringified(), field.getTargetValueStringified()) > -1}
checked.@process.checkMultiValue.@if.hasValue = ${field.hasCurrentValue()}
checked.@process.checkMultiValue.@if.isMultiple = ${field.isMultiple()}
checked.@process.checkSingleValue = ${field.getCurrentValueStringified() == field.getTargetValueStringified()}
checked.@process.checkSingleValue.@if.hasValue = ${field.hasCurrentValue()}
checked.@process.checkSingleValue.@if.isSingle = ${!field.isMultiple()}

renderer = afx`
<input
type="checkbox"
name={node.autoCreated}
value={someOtherVariable.autoCreated}
checked={props.checked}
{...node.autoCreated}
/>
`
}
}
-----
// TODO 9.0 migration: Line 26: !! You very likely need to rewrite "VARIABLE.autoCreated" to "VARIABLE.classification.tethered". We did not auto-apply this migration because we cannot be sure whether the variable is a Node.
prototype(Neos.Fusion.Form:Checkbox) < prototype(Neos.Fusion.Form:Component.Field) {

renderer = Neos.Fusion:Component {

#
# pass down props
#
attributes = ${node.classification.tethered || documentNode.classification.tethered}

#
# the `checked` state is calculated outside the renderer to allow` overriding via `attributes`
#
checked = false
checked.@process.checkMultiValue = ${Array.indexOf(field.getCurrentMultivalueStringified(), field.getTargetValueStringified()) > -1}
checked.@process.checkMultiValue.@if.hasValue = ${field.hasCurrentValue()}
checked.@process.checkMultiValue.@if.isMultiple = ${field.isMultiple()}
checked.@process.checkSingleValue = ${field.getCurrentValueStringified() == field.getTargetValueStringified()}
checked.@process.checkSingleValue.@if.hasValue = ${field.hasCurrentValue()}
checked.@process.checkSingleValue.@if.isSingle = ${!field.isMultiple()}

renderer = afx`
<input
type="checkbox"
name={node.classification.tethered}
value={someOtherVariable.autoCreated}
checked={props.checked}
{...node.classification.tethered}
/>
`
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Neos\Rector\Tests\ContentRepository90\Rules\FusionNodePathRector;

use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class FusionNodeAutoCreatedRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $fileInfo): void
{
$this->doTestFile($fileInfo);
}

/**
* @return \Iterator<string>
*/
public function provideData(): \Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture', '*.fusion.inc');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare (strict_types=1);

use Neos\Rector\Core\FusionProcessing\FusionFileProcessor;
use Rector\Config\RectorConfig;
use Neos\Rector\ContentRepository90\Rules\FusionNodeAutoCreatedRector;

return static function (RectorConfig $rectorConfig): void {
$services = $rectorConfig->services();
$services->defaults()
->public()
->autowire()
->autoconfigure();
$services->set(FusionFileProcessor::class);
$rectorConfig->disableParallel(); // does not work for fusion files - see https://github.com/rectorphp/rector-src/pull/2597#issuecomment-1190120688

$rectorConfig->rule(FusionNodeAutoCreatedRector::class);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
prototype(Neos.Fusion.Form:Checkbox) < prototype(Neos.Fusion.Form:Component.Field) {

renderer = Neos.Fusion:Component {

#
# pass down props
#
attributes = ${node.contextPath || documentNode.contextPath}

#
# the `checked` state is calculated outside the renderer to allow` overriding via `attributes`
#
checked = false
checked.@process.checkMultiValue = ${Array.indexOf(field.getCurrentMultivalueStringified(), field.getTargetValueStringified()) > -1}
checked.@process.checkMultiValue.@if.hasValue = ${field.hasCurrentValue()}
checked.@process.checkMultiValue.@if.isMultiple = ${field.isMultiple()}
checked.@process.checkSingleValue = ${field.getCurrentValueStringified() == field.getTargetValueStringified()}
checked.@process.checkSingleValue.@if.hasValue = ${field.hasCurrentValue()}
checked.@process.checkSingleValue.@if.isSingle = ${!field.isMultiple()}

renderer = afx`
<input
type="checkbox"
name={node.contextPath}
value={someOtherVariable.contextPath}
checked={props.checked}
{...node.contextPath}
/>
`
}
}
-----
// TODO 9.0 migration: Line 26: !! You very likely need to rewrite "VARIABLE.contextPath" to "Neos.Node.serializedNodeAddress(VARIABLE)". We did not auto-apply this migration because we cannot be sure whether the variable is a Node.
prototype(Neos.Fusion.Form:Checkbox) < prototype(Neos.Fusion.Form:Component.Field) {

renderer = Neos.Fusion:Component {

#
# pass down props
#
attributes = ${Neos.Node.serializedNodeAddress(node) || Neos.Node.serializedNodeAddress(documentNode)}

#
# the `checked` state is calculated outside the renderer to allow` overriding via `attributes`
#
checked = false
checked.@process.checkMultiValue = ${Array.indexOf(field.getCurrentMultivalueStringified(), field.getTargetValueStringified()) > -1}
checked.@process.checkMultiValue.@if.hasValue = ${field.hasCurrentValue()}
checked.@process.checkMultiValue.@if.isMultiple = ${field.isMultiple()}
checked.@process.checkSingleValue = ${field.getCurrentValueStringified() == field.getTargetValueStringified()}
checked.@process.checkSingleValue.@if.hasValue = ${field.hasCurrentValue()}
checked.@process.checkSingleValue.@if.isSingle = ${!field.isMultiple()}

renderer = afx`
<input
type="checkbox"
name={Neos.Node.serializedNodeAddress(node)}
value={someOtherVariable.contextPath}
checked={props.checked}
{...Neos.Node.serializedNodeAddress(node)}
/>
`
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Neos\Rector\Tests\ContentRepository90\Rules\FusionNodePathRector;

use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class FusionNodeContextPathRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $fileInfo): void
{
$this->doTestFile($fileInfo);
}

/**
* @return \Iterator<string>
*/
public function provideData(): \Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture', '*.fusion.inc');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare (strict_types=1);

use Neos\Rector\Core\FusionProcessing\FusionFileProcessor;
use Rector\Config\RectorConfig;
use Neos\Rector\ContentRepository90\Rules\FusionNodeContextPathRector;

return static function (RectorConfig $rectorConfig): void {
$services = $rectorConfig->services();
$services->defaults()
->public()
->autowire()
->autoconfigure();
$services->set(FusionFileProcessor::class);
$rectorConfig->disableParallel(); // does not work for fusion files - see https://github.com/rectorphp/rector-src/pull/2597#issuecomment-1190120688

$rectorConfig->rule(FusionNodeContextPathRector::class);
};
Loading

0 comments on commit 255ab72

Please sign in to comment.