Skip to content
Work in Progress on the Event Sourced Content Repository as installable set of packages
Branch: master
Clone or download
skurfuerst Merge pull request #94 from neos/moveNodes
Extend MoveNodeAggregate to consider disabled nodes
Latest commit f7df27e May 17, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.

Event Sourced Content Repository Collection

Build Status StyleCI

This is the package bundle you can install alongside a plain Neos to play around with the event-sourced CR.

Feature comparison


Currently worked on

🚫 Will not be supported

Feature Current CR Event Sourced CR
Create/ Edit / Delete Nodes
Shortcut Handling
Query Nodes
Cut / Copy / Paste
Move Nodes
Hide Nodes
History ()
Basic Workspaces
Workspace Module
Nested Workspaces
Undo / Redo 🚫
Setting Start / End time
Resolving Referencing Nodes 🚫
Menu Rendering
Dimension Menu Rendering
Supporting "not in menu"
Dimension Fallback
Multiple Sites
Permissions / Policy
Export / Import
Node Migrations
Node Repair
Separate Read and Write API 🚫
More convenient write API
FlowQuery is compatible
Advanced test cases 🚫
Don't use ORM, but direct SQL queries 🚫
Asynchronous operations possible 🚫
performant node moving 🚫
performant node deletion 🚫
near-constant read performance 🚫
User Interface
Ensure node deletion can be published in UI
Support Dimension Constraints



The Event Sourced Content Repository relies on a feature called (Recursive) Common Table Expressions (CTE) that require

Lateron, we will also support PostgreSQL. (We know it will work, but we did not create migrations or did testing yet).


The new code should be compatible with PHP 7.2

Getting Started / Installation

  1. Get started by cloning the master branch of the neos-development-distribution. Assuming you want to install to a directory named neos-es
git clone neos-es
cd neos-es
composer install

NOTE: PHP7.2 is recommmend

  1. Install Neos as usual, via the browser or manually:
    • define a database in Configuration/Settings.yaml
    • run ./flow doctrine:migrate
    • import the demo site using ./flow site:import --package-key=Neos.Demo
    • create a backend user using ./flow user:create --roles Administrator admin password My Admin
    • ensure that when running ./flow server:run, you get frontend output; and you can log into the backend.

In order to get the necessary code base you need to do a few things:

  1. Add neos/contentrepository-development-collection and neos/content-repository-dimensionspace dependencies as custom repositories
"repositories": [
        "type": "git",
        "url": ""
        "type": "git",
        "url": ""
  1. Set minimum-stability to dev
"minimum-stability": "dev"
  1. Set prefer-stable as true
"prefer-stable": true
  1. use the require part ot the composer.json file below:

The resulting composer.json file should look something like this:

    "config": {
        "vendor-dir": "Packages/Libraries",
        "bin-dir": "bin"
    "minimum-stability": "dev",
    "prefer-stable": true,
    "repositories": [
            "type": "git",
            "url": ""
            "type": "git",
            "url": ""
    "require": {
        "neos/neos-development-collection": "4.3.x-dev",
        "neos/flow-development-collection": "5.3.x-dev",
        "neos/demo": "@dev",

        "neos/contentrepository-development-collection": "dev-master",
        "neos/content-repository-dimensionspace": "dev-master",
        "neos/event-sourcing": "dev-master",
        "neos/neos-ui": "dev-event-sourced-patch as dev-master",
        "neos/neos-ui-compiled": "@dev",

        "neos/party": "@dev",
        "neos/seo": "@dev",
        "neos/imagine": "@dev",
        "neos/twitter-bootstrap": "@dev",
        "neos/form": "@dev",
        "neos/setup": "@dev",
        "flowpack/neos-frontendlogin": "@dev",
        "neos/buildessentials": "@dev",
        "mikey179/vfsstream": "~1.6",
        "phpunit/phpunit": "~7.1.0",
        "symfony/css-selector": "~2.0",
        "neos/behat": "~5.0.0"
    "scripts": {
        "post-update-cmd": "Neos\\Flow\\Composer\\InstallerScripts::postUpdateAndInstall",
        "post-install-cmd": "Neos\\Flow\\Composer\\InstallerScripts::postUpdateAndInstall",
        "post-package-update": "Neos\\Flow\\Composer\\InstallerScripts::postPackageUpdateAndInstall",
        "post-package-install": "Neos\\Flow\\Composer\\InstallerScripts::postPackageUpdateAndInstall"
  1. Then, run composer update.

  2. After that, run ./flow flow:package:rescan.

HINT: If you experice issues clear the Date/Temporary directory and run the command again.

  1. If using dimensions, the dimension configuration has changed. Use the following configuration in Settings.yaml for the Demo site (Adjust as needed):
        label: 'Neos.Demo:Main:contentDimensions.language'
        icon: icon-language
        defaultValue: en_US
          mode: 'uriPathSegment'
            label: 'English (US)'
              value: en
                label: 'English (UK)'
                  value: uk
            label: German
              value: de
                label: Dutch
                  value: nl
            label: French
              value: fr
            label: Danish
              value: da
            label: Latvian
              value: lv
  1. create necessary tables using ./flow doctrine:migrate

  2. create events from your (legacy) NodeData by running ./flow contentrepositorymigrate:run - this also populates the projection.

    NOTE: The output of this command is still a little weird; showing lots of var_dumps. When this command does not show a fatal error, it ran through successfully.

  3. Do a manual UI rebuild due to currently needed:

cd Packages/Application/Neos.Neos.Ui
make setup
  1. Enable FrontendDevelopmentMode in Settings.yaml:
      frontendDevelopmentMode: true
  1. The frontend should now work as expected. Test that the frontend rendering works.

  2. After logging into the backend, you might still see a fatal error. In that case manually remove the URL query parameters so that the URL is only /neos/content

  3. In case you want to start with clean events and a clean projection (after you did some changes), re-run ./flow contentrepositorymigrate:run

  4. To set up Behavioral tests, do the following:

    • install Behat: composer require --dev --prefer-source --no-interaction neos/behat ~5.0.0

    • clear the cache: rm -Rf Data/Temporary; rm -Rf Build/Behat

    • set up behat: ./flow behat:setup

    • Create a new database for behat

    • create Configuration/Testing/Behat/Settings.yaml with the following contents:

              driver: pdo_mysql
              dbname: 'YOUR-DB-NAME-HERE'
              user: 'root'
              password: ''

      Important: the driver must be set to pdo_mysql; and the DB name and user need to be specified.

  5. To run the behavioral tests, do:

    bin/behat -c Packages/CR/Neos.EventSourcedContentRepository/Tests/Behavior/behat.yml.dist

Road to first running alpha

  • create standalone package collection instead of branches
  • command to import from NodeData to events
  • make it work with Neos.ContentRepository.DimensionSpace package
  • ensure Behavioral Tests run again
  • ensure Functional Tests run again
  • figure out how/if to use event sourced Site/Domain (!possibly difficult!) -> fixed; won't use event sourced site/domain
  • change RoutePart Handler when using event-sourced mode
  • adjust NodeController when using event-sourced mode
  • add switch to use event-sourced read model in Fusion rendering (!possibly difficult due to method signatures!)
  • allow to open User Interface based on Event-Sourced read model
  • implement Show/Hide of nodes (recursively)
  • ?? implement new NodeTreeAggregate?
  • create Commands in response to UI interaction
    • SetProperty command
    • CreateNode
    • MoveNode
    • ShowNode
    • DisableNode
  • create feature list in this README, detailing what is supported and what not yet.
  • support empty content dimension values in URL; e.g. "/de/..." for german, and "/..." for english
  • absolute node referencing for ContentCollection (e.g. shared footer in Demo Site)
  • fix Policy handling to configure permissions for various UI parts
  • fix structure tree
  • show correct workspace state after reload (top publish button)
  • fix inline linking
  • fix node tree search
  • fix node tree filter
  • Implement Node Repair
  • (further TODOs here; this list is not complete yet)

Technical Description (for developers)

This section should give an overview about the different involved packages, to ease understanding the different moving parts.


see for the Pull Request.

  • in namespace Domain\Projection\Content, the new NodeInterface and TraversableNodeInterface are defined.
  • in namespace Domain\ValueObject, corresponding value objects are defined.
  • the old Neos\ContentRepository\Domain\Model\Node implements the full new NodeInterface and most of TraversableNodeInterface. This is needed to ensure we can build FlowQuery implementations which can work with old and new API at once.
  • adjusted FlowQuery operations to TraversableNodeInterface (TODO not yet all of them)


see for the Pull Request.

  • various detail improvements to use TraversableNodeInterface in the core (e.g. FusionView)


APIs to query the configured dimension space

CR / Neos.EventSourcedContentRepository

Transition package implementing the event sourced CR core. In the longer run, will probably be merged into Neos.ContentRepository.

  • Domain\Context\* implements Commands, Command Handlers, Events for Workspace, Content Stream, Nodes
  • Domain\Projection\* implements projections for changes, workspace listing; and contains the definition for the main Content Graph projection (ContentGraphInterface and ContentSubgraphInterface)

CR / Neos.ContentGraph.DoctrineDbalAdapter

implementation of the ContentGraphInterface and ContentSubgraphInterface using MySQL queries.

CR / Neos.EventSourcedNeosAdjustments

It turns out that there are numerous changes needed to the details of Neos.Neos - so this package hooks into various places in the Neos lifecycle to override certain Neos functionality.

We often completely override certain classes / behaviors from the Neos core completely; so that should make merging the changes back to the Neos.Neos package at some point a lot easier because we can then replace full classes instead of only individual pieces.

This package consists of the following bounded contexts, listed in their order during request processing:


This contains a CommandController and a service to generate events from reading NodeData. It can be activated using the new CLI command.


We replace the default FrontendNodeRoutePartHandler by providing an extra implementation of FrontendNodeRoutePartHandlerInterface.

Activation: We replace the implementation of FrontendNodeRoutePartHandlerInterface in Objects.yaml.

  • internally, the Http and Routing namespaces are used for behaviours internal to the routing.


This is a replacement for Frontend\NodeController of Neos.Neos.

Activation: We trigger this controller by AOP (in NodeControllerAspect): We call the new controller when processRequest() is called for the Neos controller.


  • We replace certain Fusion implementations which are already re-implemented to work more efficiently with the ContentGraph API; and which implement linking (because this API also changed). This includes:

    • Menu / DimensionMenu
    • NodeUri, ConvertUris
    • ContentElementEditable / ContentElementWrapping (because the ContentElementWrapping service has changed quite a lot)
    • Activation: using fusion autoInclude in Settings.yaml, we load the Fusion file resource://Neos.EventSourcedNeosAdjustments/Private/Fusion/Root.fusion. This Root.fusion replaces the implementations for the aforementioned Fusion objects, so things work as expected for integrators (without new namespaces).
  • Eel NodeHelper and WorkspaceHelper

    • Activation: These helpers are registered under the names Neos.EventSourcedNeosAdjustments.*; so a separate name. These helpers are explicitely used in the Root.fusion mentioned a few lines above.
  • custom ExceptionHandler because this also needs the replacement ContentElementWrappingService.

    • Activation: This helper is used as exception handlers in the Root.fusion mentioned a few lines above.
    • If people used these exception handlers themselves, they need to reconfigure them to the new implementations.


  • We replace Linking and Content Element Wrapping ViewHelpers, because Node Linking has changed and ContentElementWrapping has changed as well.
    • Activation: Using AOP, the ViewHelperReplacementAspect implements aliasing of ViewHelper classes; effectively returning the VHs in this namespace instead of the default ones.


We implement a completely new ContentElementWrappingService and ContentElementWrappingService; mainly because they change quite a bit and their interfaces now require TraversableNodeInterface instead of the legacy NodeInterface.

The new services are used in the overridden ViewHelpers (see section Fluid above); and in overridden Fusion implementations (see section Fusion above).

NodeAddress (Domain\Context\Content)

A NodeAddress is an external representation of a node (used in routing). TODO: Move to Neos.EventSourcedContentRepository.


  • BackendController is an alternative implementation for Neos.Neos.Ui BackendController.
    • Activation: We trigger this controller by AOP (in BackendControllerAspect): We call the new controller when processRequest() is called for the Neos backend controller.
  • We create Content Streams on backend login using the EditorContentStreamZookeeper (TODO change name maybe?).
    • Activation: We trigger this service by Signal/Slot in Package.php.
  • Fusion (for backend)
    • Activation: We load a custom resource://Neos.EventSourcedNeosAdjustments/Private/Fusion/Backend/Root.fusion using Views.yaml.
    • custom NodeInfoHelper, calling to a custom NodePropertyConverterService
  • adjust the DimensionSwitcher JS component in Resources/Private/UiAdapter
  • TODO: this is not everything yet.
You can’t perform that action at this time.