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: References on creation and Copy #5148

Merged
merged 34 commits into from
Nov 1, 2024

Conversation

kitsunet
Copy link
Member

@kitsunet kitsunet commented Jun 17, 2024

This reworks references so that multiple reference properties can be set via a single command and also references can be attached to CreateNodeAggregateWithNode which is also used for copying nodes.

The serialization format is adapted to allow multiple reference properties, which also affects all behat tests with references.

To migrate existing events run:

./flow migrateevents:migratesetreferencestomultinameformat

Marked breaking as it requires an event migration.

This requires neos/neos-ui#3844 for the UI

A behat test to show reference copies work was added.

Upgrade Instructions

The API to set references changed a little, please adjust accordingly.
This is a simple example which covers all cases:

SetNodeReferences::create(
    $node->workspaceName,
    $node->aggregateId,
    $node->originDimensionSpacePoint,
    NodeReferencesToWrite::create(
        // sets the 3 nodes as references
        NodeReferencesForName::fromTargets(
            ReferenceName::fromString('first-reference'),
            NodeAggregateIds::fromArray(['node-aggregate-id-1', 'node-aggregate-id-2', 'node-aggregate-id-3'])
        ),
        // unset previously set references (as we do NOT merge the values)
        NodeReferencesForName::createEmpty(
            ReferenceName::fromString('second-reference')
        ),
        // create a simple node reference and additionally a reference with an additional property
        NodeReferencesForName::fromReferences(
            ReferenceName::fromString('third-reference'),
            [
                NodeReferenceToWrite::fromTarget(NodeAggregateId::fromString('node-aggregate-id-6')),
                NodeReferenceToWrite::fromTargetAndProperties(NodeAggregateId::fromString('node-aggregate-id-5'), PropertyValuesToWrite::fromArray([
                    'propertyOnReference' => 'Hi im living on the edge ;)'
                ])),
            ])
        )
    )
)

@kitsunet
Copy link
Member Author

Do not merge yet, probably want to refactor some of the code in the DTOs. I think we should make the "collection of references for one reference property" an explicit DTO, as the code like this feels a bit too messy for my taste...

@kitsunet
Copy link
Member Author

kitsunet commented Jun 17, 2024

On the upside the somewhat weird and unfinished reference snapshots can be removed with this.

@kitsunet
Copy link
Member Author

kitsunet commented Jun 17, 2024

And forgot to adapt legacy migration tests (which rely on specific event payloads, see below, before I adjust those we should decide which way to go with b/c)...

@kitsunet
Copy link
Member Author

oh and I should mention that at the moment this is not forgiving to the existing events. We could do this in the respective fromArray constructors of the DTOs and just "upcast" from the old structure on the fly without much problem, or add a migration for the events.

Copy link
Member

@mhsdesign mhsdesign left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this, some early thoughts before ill play with this ;)

@kitsunet
Copy link
Member Author

Screenshot 2024-06-18 at 08 47 52

I think this would be much nicer code wise (obviously duplicated for Serialized...), bit annoying to use 3 objects for this, but I think it will make the code much better to reason with and empty is then really just the new "middle DTO" with createEmpty()

This reworks references so that multiple reference properties can be
set via a single command and also references can be attached to
`CreateNodeAggregateWithNode` which is also used for copying nodes.
@kitsunet kitsunet force-pushed the feature/node-reference-copy branch from 1ee4c27 to 1612659 Compare August 23, 2024 12:20
# Conflicts:
#	Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php
@mhsdesign
Copy link
Member

I remember we discussed this some time ago so i was wondering where it goes from now? I think we discussed for an alternative way than to use a "hacky" NodeReferenceNameToEmpty?

@kitsunet kitsunet changed the title FEATURE: References on creation and Copy !!! FEATURE: References on creation and Copy Oct 23, 2024
Copy link
Member

@mhsdesign mhsdesign left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ill re review later:)

@mhsdesign mhsdesign mentioned this pull request Oct 30, 2024
4 tasks
Copy link
Member

@bwaidelich bwaidelich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work.. and a lot of it, yikes.
Some rather minor issues

Comment on lines +55 to +71
$this->getDatabaseConnection()->delete($this->tableNamePrefix . '_referencerelation', [
'sourcenodeanchor' => $anchorPoint->value,
'name' => $referencesForProperty->referenceName->value
]);

foreach ($referencesForProperty->references as $reference) {
// set new
$referenceRecord = new ReferenceRelationRecord(
$anchorPoint,
$referencesForProperty->referenceName,
$position,
$reference->properties,
$reference->targetNodeAggregateId
);
$referenceRecord->addToDatabase($this->getDatabaseConnection(), $this->tableNamePrefix);
$position++;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, can't we turn this into two atomic queries?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for me the pg adapter is out of scope and there are no tests ... but i fixed it for doctrine

$this->requireNodeTypeToDeclareReference($sourceNodeAggregate->nodeTypeName, $referenceName);
$scopeDeclaration = $sourceNodeType->getReferences()[$referenceName->value]['scope'] ?? '';
$scope = PropertyScope::tryFrom($scopeDeclaration) ?: PropertyScope::SCOPE_NODE;
// TODO: Optimize affected sets into one event
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific reason why we don't?
The current state would be like publishing multiple NodePropertiesWereSet events for each property.

Couldn't we just build up the $referencesByName array and then build the event outside of the loop?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjusted:)

@mhsdesign
Copy link
Member

and the test has to be adjusted as it fails now earlier:

001 Scenario: Node reference cannot hold multiple targets to the same node                                          # Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature:190
      Then the last command should have thrown an exception of type "InvalidArgumentException" with code 1700150910 # Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature:195
        Expected exception code 1700150910, got exception code 1730365958 instead; Message: Duplicate entry in references to write. Target "anthony-destinode" already exists in collection.
        Failed asserting that 1730365958 is identical to 1700150910.

@mhsdesign
Copy link
Member

Okay i fixed the tests again and added some documentation ... i also got rid of the duplicate NodeReferencesToWrite::fromReferences and its now just create and also the fromNameAnd parts are out for the NodeReferencesForName as well its guaranteed to stick to a name and thus makes it a little shorter and hopefully easy to use.

SetNodeReferences::create(
    $node->workspaceName,
    $node->aggregateId,
    $node->originDimensionSpacePoint,
    NodeReferencesToWrite::create(
        // sets the 3 nodes as references
        NodeReferencesForName::fromTargets(
            ReferenceName::fromString('first-reference'),
            NodeAggregateIds::fromArray(['node-aggregate-id-1', 'node-aggregate-id-2', 'node-aggregate-id-3'])
        ),
        // unset previously set references (as we do NOT merge the values)
        NodeReferencesForName::createEmpty(
            ReferenceName::fromString('second-reference')
        ),
        // create a simple node reference and additionally a reference with an additional property
        NodeReferencesForName::fromReferences(
            ReferenceName::fromString('third-reference'),
            [
                NodeReferenceToWrite::fromTarget(NodeAggregateId::fromString('node-aggregate-id-6')),
                NodeReferenceToWrite::fromTargetAndProperties(NodeAggregateId::fromString('node-aggregate-id-5'), PropertyValuesToWrite::fromArray([
                    'propertyOnReference' => 'Hi im living on the edge ;)'
                ])),
            ])
    )
)

... like in set serialized properties.

That way fewer `NodeReferencesWereSet` are emitted.
At most only one per scope of `PropertyScope`

Also the `PropertyScope` enum was marked internal as its not exposed in apis and no use for the user.
Copy link
Member

@mhsdesign mhsdesign left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay i further made the optimisations basti suggested. Now its truly finished id say <3

Thank you so much for your effort!

@kitsunet kitsunet enabled auto-merge November 1, 2024 10:17
@kitsunet kitsunet disabled auto-merge November 1, 2024 10:17
@kitsunet kitsunet merged commit 4d00a25 into neos:9.0 Nov 1, 2024
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants