Introducing the concept of workspaces. Content entities always belong to a workspace (there is one main exception, which is the user entity type). A workspace is a silo/container of content on a site. However, this phase only introduces the underlying concept with one single workspace available, without many supporting APIs around it (see later phases). This phase will not change any UIs or behaviours in core.
See Workspace module for the current contrib implementation.
- Define the workspace entity itself
- Introduce the workspace reference field for all content entity types
- Extend storage handlers to work with workspaces
Architecture overview
- Workspaces are content entities.
- A "live" and "stage" workspace is created on installation.
- The default workspace (the one anonymous users see) is set in workspace.services.yml as a parameter.
- Workspaces depend on revisionable and publishable content, therefore only Nodes are supported.
- No queries, entity loads, or anything are altered for the default workspace.
- Content is linked to a workspace via a ContentWorkspace entity (similar to Content Moderation's ContentModerationState entity).
- All content added on non-default workspaces is saved as unpublished. The real published states is saved against the ContentWorkspace entity.
- There is a computed entity_reference field "workspace" added to all entity types that can belong to a workspace.
- An entity query alter is performed on non-default workspaces to join the ContentWorkspace entity field revision table and only load entities which are in the active (current) or default workspace.
- A Views query alter is done in the a similar way to the entity query alter, although here we also take into account the published status from the ContentWorksapce entity if the View has a published filter.
- In hook_entity_load we switch out the entity revision for the correct one for the current active workspace based on data stored in the ContentWorkspace entity. The published status is also switched if needed.
- Each workspace can have an upstream, this is like a git upstream, when deploying content is replicated to the upstream.
- Upstreams are plugins. In the workspace module these are derived from workspaces. Contrib could hook into this to make upstreams anything, other sites, non-drupal apps, etc.
- Replication is handled by a tagged service, again, this allows contrib to hook in and provide different replication.
- The default replicator looks for changes between two workspaces then loops through all these revisions and saves them on the target workspace.
- Each replication creates a replication log entity. For the default replicator this is based on an MD5 hash of the source and target workspaces, so when replicating again between those two workspaces we know what replications have already happened.
- All entity updates create an entity in the sequence index. This index is also used in replication two find the changes since the last replication.
- The user's active workspace is determined via a negotiator, so it can either come from the container parameter (default workspace) or a session value.
- There is complex access checks which will allow you to lock down users to only create content in specific workspaces.
- The active workspace is switched by either using the toolbar.module integration, or enabling a switcher block.