Neos 9 Beta-16 Release

Today we released yet another Neos 9 Beta.

This is partially still the aftermath of the Neos sprint and also what we were able to accomplish in the last week :slight_smile:

Thanks to all who contributed <3.

Upgrade instructions from Beta 15

previous beta → Neos 9 Beta-15 Release

In your composer.json you should require 9.0.0-beta16 for all Neos packages from the development distribution and for the NeosUi as well as Flow:

"neos/flow": "9.0.0-beta16",
"neos/neos": "9.0.0-beta16",
"neos/neos-ui": "9.0.0-beta16"

The database can be migrated the following way:

A setup to apply the latest schema adjustments:

./flow doctrine:migrate
./flow cr:setup

Additionally, PRs marked with :boom:⛁ need a dedicated migration

  • :boom:⛁¹ Migration in order for the live workspace to be publicly visible
./flow workspace:assignrole live "Neos.Flow:Everybody" viewer
  • :boom:⛁² (Optional!) Migration to fix copy of tethered nodes
./flow migrateevents:migratecopytetherednode

(This migration is only needed if replaying or the backend throws exceptions like: The NodeName must be set if the Node is tethered.)

  • :boom:⛁³ (Optional!) Migration to reorder node removal events
# note the error "Writable events must contain at least one event" indicates the command was not required, sorry :D Everything is okay ^^
./flow migrateevents:reordernodeaggregatewasremoved

(This migration is only needed if replaying does not work and throws exceptions like: Failed to move node "000000000" in sub graph 000000000 because it does not exist or Cannot update node with copy on write since no anchor point could be resolved for node 000000000 in content stream 000000000)

NOTE the migration will cause all workspaces to be outdated and contain the removed nodes again before synching. After synchronisation (rebase) this is fixed.

  • :boom:⛁⁴ Status check for legacy copy nodes events

Also note that as copy nodes has been refactored, the legacy copy nodes events must be published to the live workspace before the final release of Neos 9.
To detect those cases please use:

./flow migrateevents:copynodesstatus

Features

1.) :sparkles: Highlight :sparkles: Content Repository Privileges

Introduces basic security to the event sourced content repository


PHP Api changes

Adjustments to VisibilityConstraints:

The method VisibilityConstraints::frontend() was renamed to VisibilityConstraints::default().
But for the cases you have used VisibilityConstraints at all - as mandatory argument for getSubgraph you can now simplify that to use getContentSubgraph directly:

before

$subgraph = $contentRepository->getContentGraph($nodeAddress->workspaceName)->getSubgraph(
    $nodeAddress->dimensionSpacePoint,
    $nodeAddress->workspaceName->isLive() ? VisibilityConstraints::frontend() : VisibilityConstraints::withoutRestrictions()
);

after

$subgraph = $contentRepository->getContentSubgraph($nodeAddress->workspaceName, $nodeAddress->dimensionSpacePoint);

Note that getContentGraph(...)->getSubgraph(...) still works but is only meant to be used if your you want to determine the VisibilityConstraints for some case differently.


Usage

Workspace Permissions

The following workspace roles exist:

  • VIEWER: Can read from the workspace
    • By default, everybody is a VIEWER to the live workspace
  • COLLABORATOR: Can read from and write to the workspace
  • MANAGER: Can read from and write to the workspace and manage it (i.e. change metadata & role assignments)

Furthermore, personal workspaces can be owned by a particular user. The workspace owner implicitly has the MANAGER role, i.e. has full access to that workspace.

Workspace roles are transitive. That means that COLLABORATOR has all privileges of the VIEWER and MANAGER has all privileges of the COLLABORATOR

To publish changes to a workspace, the authenticated user has to have at least the VIEWER role on the workspace to publish and COLLABORATOR role on the target workspace.

Workspace role assignments will be changeable with the new workspace module or via CLI:

./flow workspace:assignrole

ReadNodePrivilege

In general, the ReadNodePrivilege works like it did before Neos 9: It allows to completely hide sub trees of the content repository from a given user group.
But the implementation and configuration format has changed.

This is how a ReadNodePrivilege can be configured via Policy.yaml:

privilegeTargets:
  'Neos\Neos\Security\Authorization\Privilege\ReadNodePrivilege':
    'Neos.Demo:ReadBlog':
      matcher: 'blog'

The matcher refers to a SubtreeTag, so this example would hide all nodes that are tagged with blog (including their descendants) from all users that don’t have a GRANT on that specific privilege target.

By default, the privilege is active for all configured content repositories. By prefixing the matcher with <content-repository-id>: this can be limited to a specific CR (for example default:blog)

EditNodePrivilege

Likewise the purpose of the EditNodePrivilege is like before Neos 9: To restrict certain users from changing nodes (includes creation, setting properties or references, disabling/enabling, tagging and moving, …) in a given subtree.

The new configuration syntax is similar to the one for ReadNodePrivilege:

privilegeTargets:
  'Neos\Neos\Security\Authorization\Privilege\EditNodePrivilege':
    'Neos.Demo:EditBlogNodes':
      matcher: 'blog'

Again, the matcher refers to a SubtreeTag, so this example would disallow users without a corresponding GRANT permission to edit nodes in the subtree that is tagged blog.

Both privileges expect a subtree to be tagged. That is not yet possible via the Neos UI or CLI but requires interaction with the PHP API ($contentRepository->handle(TagSubtree::create(....))) – we’ll provide a way to do that, follow #3732 for updates


Removed privilege types

The following Content Repository privilege types have been removed because their behavior was inconsistent and/or because they led to (performance) issues: NodeTreePrivilege, CreateNodePrivilege, ReadNodePropertyPrivilege, EditNodePropertyPrivilege

We will most probably re-add some of the functionality in a future version, but for now you can implement the AuthProviderInterface in order to enforce custom authorization requirements.


Examples

Disallow a role to edit nodes of a subtree

With the following Policy.yaml:

privilegeTargets:
  'Neos\Neos\Security\Authorization\Privilege\EditNodePrivilege':
    'Neos.Demo:EditBlogNodes':
      matcher: 'blog'
roles:
  'Neos.Neos:Administrator':
    privileges:
      -
        privilegeTarget: 'Neos.Demo:EditBlogNodes'
        permission: GRANT

only administrators are allowed to edit nodes in the blog subtree.

The Neos UI does not currently properly reflect readonly nodes – The inspector will be empty and inline editable fields will be editable – but changing their content will lead to an AccessDenied exception

In order to also hide the uneditable subtree, the following can be added:

privilegeTargets:
  # ...
  'Neos\Neos\Security\Authorization\Privilege\ReadNodePrivilege':
    'Neos.Demo:ReadBlogNodes':
      matcher: 'blog'
roles:
  'Neos.Neos:Administrator':
    privileges:
      # ...
      -
        privilegeTarget: 'Neos.Demo:ReadBlogNodes'
        permission: GRANT

Allow a role to only edit within a given subtree

To achieve the opposite of the above, granting a user group to only edit nodes within a subtree, the whole tree must be tagged (i.e. the homepage node, all descendants will inherit the tag).

With all nodes being tagged demosite and the blog nodes beeing tagged blog in addition, the following Policy.yaml will do:

privilegeTargets:
  'Neos\Neos\Security\Authorization\Privilege\EditNodePrivilege':
    'Neos.Demo:EditAnyNode':
      matcher: 'demosite'
    'Neos.Demo:EditBlogNodes':
      matcher: 'blog'
roles:
  'Neos.Neos:Administrator':
    privileges:
      -
        privilegeTarget: 'Neos.Demo:EditAnyNode'
        permission: GRANT
  'Neos.Neos:Editor':
    privileges:
      -
        privilegeTarget: 'Neos.Demo:EditBlogNodes'
        permission: GRANT

With that, the administrator will be able to edit any node, but editors can only edit nodes within the blog subtree.

(thanks bastian for the great documentation <3)

2.) Overhauled Node Copying

The new service copies the specified source node and its children to the target node

Note about dimensions

Currently the copying is primitive as that we take the read-model of the dimension to copy (the subgraph). and paste that into the target dimension.
That means that the copy does not alter other dimensions and that virtual variants are materialised.
For more information see {@link BUG: CopyNodesRecursively vs Content Dimensions · Issue #5054 · neos/neos-development-collection · GitHub}

Note about constraints

As we cannot rely on the full integrate on the subgraph regarding the current node type schema it might not be possible to copy a node and its children.
For example copying a node with tethered children that is not tethered according to the current node type schema, or copying properties that are not defined
in the current node type schema anymore. In those cases the structure adjustments have to be executed. (todo only copy what is applicable and be graceful)

Note about partial copy on error

As the above mentioned constraints can fail and we handle the determined content repository commands one by one, a failure will lead to a partially evaluated copy.
The content repository is still consistent but the intent is only partially fulfilled.


PHP Api changes

Instead of using CopyNodesRecursively::createFromSubgraphAndStartNode and handling that in the CR, please use:

#[Flow\Inject()]
protected NodeDuplicationService $nodeDuplicationService;

// ...

$this->nodeDuplicationService->copyNodesRecursively(
    $contentRepositoryId,
    $workspaceName,
    $sourceDimensionSpacePoint,
    $sourceNodeAggregateId,
    $targetDimensionSpacePoint,
    $targetParentNodeAggregateId,
    $targetSucceedingSiblingNodeAggregateId
);

3.) :sparkles: Highlight :sparkles: High level site import

Add commands site:importall, site:exportall and site:pruneall to import export and prune all sites of the given content repository.
This will export events files and sites into a package (Resources/Private/Content) or any other specified target directory.

For example importing the Neos Demo looks like

./flow site:importall --package-key Neos.Demo

The previously available commands cr:import, cr:export and cr:prune were removed because those did not take the site nodes into account.

Additionally, the command ./flow cr:migrateLegacyData was renamed and behaviour changed. In order to migrate Neos 8.3 to Neos 9.0 please use:

# the following config points to a Neos 8.0 database (adjust to your needs)
./flow site:exportlegacydata --path ./migratedContent --config '{"dbal": {"dbname": "neos80"}, "resourcesPath": "/path/to/neos-8.0/Data/Persistent/Resources"}'
# import the migrated data
./flow site:importall --path ./migratedContent

4.) Extension point to hook into command handling

With custom projections and CatchUpHooks we already provide two clean extension points.
With command hooks we provide a way to modify a command before it is handled.
Previously this was possible with the Signal/Slot mechanism for nodes (e.g. nodePropertyChanged).

Common use cases are:

  • enforcing unique properties
  • adding some custom version numbering for imports
  • calculating derived properties

And example implementation of the CommandHookInterface can be found in the Neos Formbuilder package, the UniqueIdentifierCommandHook see FEATURE: Ensure unique form element identifier with a CommandHook by dlubitz · Pull Request #142 · neos/form-builder · GitHub

5.) Improve catchup hooks

Improves the performance of the asset usage and content cache catchup hook by introducing the query findAncestorNodeAggregateIds.
Additionally the wiring for custom catchup hooks changed, please adjust accordingly.

Bugfixes

Neos Content Repository

Dev only relevant

List of things

Neos

Flow

5 Likes

For the rare case an exception is thrown while replay like

Failed to insert node: An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ‘…’ for key ‘variant’

the migrateevents:reordernodeaggregatewasremoved events migration was a little to aggressive and needs to be patched.
As described here Bugfix: Only reorder `NodeAggregateWasRemoved` events if the node is not recreated afterwards by mhsdesign · Pull Request #5382 · neos/neos-development-collection · GitHub this is only a problem when having build a cr importer or the like.

In this case please use the automatically created events backup and reapply the patched migration.

{
    "name": "your/distribution",
    "config": {
        "allow-plugins": {
          // ...
          "cweagans/composer-patches": true
        }
    },
    "require": {
      // ...
      "cweagans/composer-patches": "^1.7.3"
    },
    "extra": {
      "patches": {
        "neos/contentrepositoryregistry": {
          "Bugfix: Only reorder NodeAggregateWasRemoved events if the node is not recreated afterwards": "https://github.com/neos/neos-development-collection/pull/5382.patch"
        }
      }
    }
}
1 Like