eZ Systems Website
  Editor documentation

  Developer documentation

  Back to the top

The documentation is moving!

We're moving our developer docs to Github and a new site.
The migration is still in progress, so please contact us in #documentation-contrib on eZ Community Slack if you have any questions or feedback.

This space will not be updated from now on except for critical fixes.

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 9 Next »



A Content item could not function in the system without having a place – a Location – assigned to it. When a new Content item is published, a new Location is automatically created and the item is placed in it.

Together, all Locations form a tree which is the basic way of organizing Content in the system and specific to eZ products. Every published Content item has a Location and, as a consequence, also a place in this tree.

A Content item receives a Location only once it has been published. This means that a freshly created draft does not have a Location yet.

A Content item can have more than one Location. This can be used to have the same content in two or more places in the tree, for example an article at the same time on the front page and in the archive. Even in such a case, one of these places is always the Main Location.

The tree is hierarchical, with an empty root Location (which is not assigned any Content item) and a structure of dependent Locations below it. Every Location (aside from the root) has one parent Location and can have any number of children. There are no Locations outside this tree.

Top level Locations

Top level Locations are direct children of the root of the tree. There are three preset top level Locations in each installation which cannot be deleted:


"Content" is the top level Location for the actual contents of a site. This part of the tree is typically used for organizing folders, articles, information pages, etc. This means that it contains the actual content structure of the site, which can be viewed by selecting the "Content structure" tab in the Content mode interface. The default ID number of the "Content" Location is 2; it references a "Folder" Content item.


"Media" is the top level Location which stores and organizes information that is frequently used by Content items located below the "Content" node. It usually contains images, animations, documents and other files. They can be viewed by selecting the "Media library" tab in the Content mode interface. The default ID number of the "Media" Location is 43; it references a "Folder" Content item.


"Users" is the top level Location that contains the built-in system for managing user accounts. A user is simply a Content item of the "User account" Content Type. The users are organized within "User group" Content items below this Location. In other words, the "Users" Location contains the actual users and user groups, which can be viewed by selecting the "Users" tab in the Admin Panel. The default identification number of the "Users" Location is 5; it references a "User group" Content item.

Location visibility

Location visibility is a mechanism which allows you to control which parts of the content tree are available to the visitor.

Given that once a Content item is published, it cannot be un-published, limiting visibility is the only method used to withdraw content from the website without moving it to Trash. When the Location of a Content item is hidden, any access to it will be denied, preventing the system from displaying it.

Visibility needs not be set individually for every Location. Instead, when a Location is hidden, all of its descendants in the tree will be hidden as well. This means that a Location can have one of three different visibility statuses:

  •  Visible
  •  Hidden
  •  Hidden by superior

By default all Locations are Visible. If a Location is made invisible manually, its status is set to Hidden. At the same time all Locations under it will change status to Hidden by superior.

From the visitor's perspective a Location behaves the same whether its status is Hidden or Hidden by superior – it will be unavailable in the website. The difference is that a Location Hidden by superior cannot be revealed manually. It will only become visible once all of its ancestor Locations are made Visible again.

A Hidden by superior status does not override a Hidden status. This means that if a Location is Hidden manually and later one of its ancestors is Hidden as well, the first Location's status does not change – it remains Hidden (not Hidden by superior). If the ancestor Location is made visible again, the first Location still remains Hidden.

The way visibility works can be illustrated using the following scenarios:

Hiding a visible Location

Hiding a visible Location

When you hide a Location that was visible before, it will get the status Hidden. Underlying Locations will be marked Hidden by superior. The visibility status of underlying Locations that were already Hidden or Hidden by superior will not be changed.

Hiding a Location which is Hidden by superior

Hiding a Location which is Hidden by superior


When you explicitly hide a Location which was Hidden by superior, it will get the status Hidden. Since the underlying Locations are already either Hidden or Hidden by superior, their visibility status will not be changed.

Revealing a Location with a visible ancestor

Revealing a Location with a visible ancestor


When you reveal a Location which has a visible ancestor, this Location and its children will become visible. However, underlying Locations that were explicitly hidden by a user will retain the Hidden status (and their children will be remain Hidden by superior).

Revealing a Location with a Hidden ancestor

Revealing a Location with a Hidden ancestor


When you reveal a Location that has a Hidden ancestor, it will not become Visible itself. Because it still has invisible ancestors, its status will change to Hidden by superior.

In short: a Location can only be Visible when all of its ancestors are Visible as well.

Visibility mechanics

The visibility mechanics are controlled by two flags: Hidden flag and Invisible flag. The Hidden flag informs whether the node has been hidden by a user or not. A raised Invisible flag means that the node is invisible either because it was hidden by a user or by the system. Together, the flags represent the three visibility statuses:

Hidden flagInvisible flagStatus
--The Location is visible.
11The Location is invisible and it was hidden by a user.
-1The Location is invisible and it was hidden by the system because its ancestor is hidden/invisible.


Sections are used to divide Content items in the tree into groups that are more easily manageable by content editors. Division into Sections allows you, among others, to set permissions for only a part of the tree.

Technically, a Section is simply a triplet: a number, a name and an identifier. Content items are placed in Sections by being assigned the Section ID, with one item able to be in only one Section.

When a new Content item is created, its Section ID is set to the default Section (which is usually Standard). When the item is published it is assigned to the same Section as its parent. Because Content must always be in a Section, unassigning happens by choosing a different Section to move it into . If a Content item has multiple Location assignments then it is always the Section ID of the item referenced by the parent of the main Location that will be used. In addition, if the main Location of a Content item with multiple Location assignments is changed then the Section ID of that item will be updated.

Sections can only be removed if no Content items are assigned to them. Even then, it should be done carefully. When a Section is deleted, it is only its definition itself that will be removed. Other references to the Section will remain and thus the system will most likely be in an inconsistent state.That is why removing Sections may corrupt permission settings, template output and other things in the system.

Section ID numbers are not recycled. If a Section is removed, its ID number will not be reused when a new Section is created.

Sections screen


Permissions in Platform form one of the most advanced permissions systems around, allowing you to define very fine-grained rights for your Editors, Visitors, Members and other users.


In the permission system a User by default does not have access to anything. To get access they need to inherit Roles, typically assigned to the User Group they belong to.



First part of the permission model is the Roles, and they consist of the following parts:

RoleLimitation *- RoleAssignment >- Role -< Policy -*< Limitation
  • A Role assignment can optionally have a Limitation, Role Limitation examples: SubTreeLimitation or SectionLimitation
  • A Role can have several assignments, Role example: Editor, Member, ProSubscriber
  • A Role consists of several Policies, Policy example: content/read/*, content/edit/* (where * refers to full access, that is no Limitation)
  • A Policy optionally consists of several Limitations, Limitation example:ContentTypeLimitation,SectionLimitation,OwnerLimitation


Second part of the model is made up of Users and User Groups:

User -*< UserGroup
  • A User can be member of several User Groups, User Group examples: Administrator Users, Member Users, ProSubscriber Users

Role assignments

Last part on the permission model is the fact that Role assignments can be assigned to both Users and User Groups:

User - RoleAssignment - UserGroup


Best Practice

Best practice is to avoid assigning Roles to Users directly, and instead to make sure you model your content (types, structure, sections, etc.) in a way that can be reflected in generic roles. Besides being much easier to manage and keep on top of security-wise, this also makes sure your system performs best. The more Role assignments and complex Policies you add for a given User, the more complex the search/load queries powering the whole CMS will be, as they always take permissions into account.

Persistence Cache


This page describes how Persistence cache works, and how to reuse the cache service it uses.


For configuring the cache service, look at the Persistence cache configuration page, for re-using the internal cache service see Usage: Using Cache service.



Persistence cache can best be described as an implementation of SPI\Persistence that decorates the main backend implementation (currently: "Legacy Storage Engine").

As shown in the illustration, this is done in the exact same way as the SignalSlot feature is a custom implementation of API\Repository decorating the main Repository. In the case of Persistence Cache, instead of sending events on calls passed on to the decorated implementation, most of the load calls are cached, and calls that perform changes purge the affected caches. This is done using a Cache service which is provided by StashBundle; this Service wraps around the Stash library to provide Symfony logging / debugging functionality, and allows cache handlers (Memcached, Redis, Filesystem, etc.) to be configured using Symfony configuration. For how to reuse this Cache service in your own custom code, see below.

Transparent cache

With the persistence cache, just like with the HTTP cache, eZ Platform tries to follow principles of "Transparent caching", this can shortly be described as a cache which is invisible to the end user and to the admin/editors of eZ Platform where content is always returned "fresh". In other words, there should be no need to manually clear the cache like it was frequently the case with eZ Publish 4.x. This is possible thanks to an interface that follows CRUD (Create Read Update Delete) operations per domain, and the fact that the number of other operations capable of affecting a certain domain is kept to a minimum.

Entity stored only once

To make the transparent caching principle as effective as possible, entities are, as much as possible, only stored once in cache by their primary id. Lookup by alternative identifiers (identifier, remoteId, etc.) is only cached with the identifier as cache key and primary id as its cache value, and compositions (list of objects) usually keep only the array of primary id's as their cache value.

This means a couple of things:

  • Memory consumption is kept low
  • Cache purging logic is kept simple (For example: $sectionService->delete( 3 ) clears "section/3" cache entry)
  • Lookup by identifier and list of objects needs several cache lookups to be able to assemble the result value
  • Cache warmup usually takes several page loads to reach full as identifier is first cached, then the object

What is cached?

Persistence cache aims at caching most SPI\Persistence calls used in common page loads, including everything needed for permission checking and url alias lookups.


  • UrlWildCardHandler is not currently cached
  • Currently in case of transactions this is handled very simply by clearing all cache on rollback, this can be improved in the future if needed.
  • Some tree/batch operations will cause clearing all persistence cache, this will be improved in the future when we change to a cache service cable of cache tagging.
  • Search is not defined as Persistence and the queries themselves are not planned to be cached. Use Solr which does this for you to improve scale and offload your database.

For further details on which calls are cached or not, and where/how to contribute additional caches, check out the source.



Two parts of the permissions system are extensible from a programmatic perspective: Policies and Limitations



  • No labels