You are viewing an old version of this page. View the current version.
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 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:
- 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
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
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
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
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.
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 flag||Invisible flag||Status|
|-||-||The Location is visible.|
|1||1||The Location is invisible and it was hidden by a user.|
|-||1||The Location is invisible and it was hidden by the system because its ancestor is hidden/invisible.|
Content items are located in a tree structure through the Locations they are placed in. However, Content items themselves can also be related to one another.
A Relation can be created between any two Content items in the repository. This feature is typically used in situations when you need to connect and/or reuse information that is scattered around in the system. For example, it allows you to add images to news articles. Instead of using a fixed set of image attributes, the images are stored as separate Content items outside the article.
There are different types of Relations available in the system. First of all, content can be related on item or on Field level.
Relations at Field level are created using one of two special Field Types: Content relation (single) and Content relations (multiple). As the names suggest, such Fields allow you to select one or more other Content items in the Field value, which will be linked to these Fields. Content relation (single) is an example of a one-to-one relationship, and Content relations (multiple) – a one-to-many relationship.
Relations at item level can be of three different types:
- Common relations are created between two Content items using the Public API.
- RichText linked relations are created using a Field of the RichText type. Whenever an internal link (a link to another Location or Content item) is inserted into a Field represented by this Field Type, the system will automatically create a relation of this type. Note that such a relation is automatically removed from the system when the corresponding link is removed from the Content item.
- RichText embedded relations also use a RichText Field. Whenever an Embed element is inserted into a Field represented by this Field Type, the system will automatically create a relation of this type, that is relate the embedded Content item to the one that is being edited. Note that a relation of this type is automatically removed from the system when the corresponding element is removed.
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.
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
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 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.
This page describes how Persistence cache works, and how to reuse the cache service it uses.
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.
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 (
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
identifierand 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.
UrlWildCardHandleris 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.
Content Repository Configuration
The content repository is where all your content is been stored. It is the heart of eZ Platform which you interact with using Public API.
To store data, the content repository uses a storage engine that can virtually can work with any kind of storage (RDBMS, NoSQL, etc.). eZ Publish 5 came with a relational storage engine, compatible with v4.x: the Legacy storage engine, which is the default.
You can define several repositories within a single application. However, you can only use one per site.
Using default values
If no repository is specified for a siteaccess or siteaccess group, the first defined repository (under
ezpublish.repositories) will be used.
Legacy storage engine
Doctrine ORM is not provided by default. If you want to use it, you will need to add
doctrine/orm as a dependency in your
Field groups configuration
Field groups, used in content and Content Type editing, can be configured from the repository section. Values entered there are field group identifiers:
These identifiers can be given human-readable values and translated. Those values will at the moment be used when editing Content Types. The translation domain is
This file will define English names for field groups:
Persistence cache configuration
Use of Memcached (or experimentally using Redis) is a requirement for use in Clustering setup. For an overview of this feature, see Clustering.
The cache system is exposed as a "cache" service, and can be reused by any other service as described on the Using Cache service page.
By default, configuration is currently using FileSystem, with
%kernel.cache_dir%/stash to store cache files.
The configuration is placed in
app/config/config.yml and looks like this:
Note for "inMemory" cache with long running scripts
inMemory with caution, and avoid it completely for long running scripts for the following reasons:
- It does not have any limits, so can result in the application running out of PHP memory.
- Its cache pool is by design a PHP variable and is not shared across requests/processes/servers, so data becomes stale if any other concurrent activity happens towards the repository.
Multi repository setup
ezplatform.yml you can specify which cache pool you want to use on a siteaccess or sitegroup level. The following example shows use in a sitegroup:
One cache pool for each repository
Stash cache backend configuration
To check which cache settings are available for your installation, run the following command in your terminal:
This cache backend uses the local filesystem, by default the Symfony cache folder. As this is per server, it does not support multi server (! ) setups
|The path where the cache is placed; default is |
|Number of times the cache key should be split up to avoid having too many files in each folder; default is 2.|
|The permissions of the cache file; default is 0660.|
|The permission of the cache file directories (see dirSplit); default is 0770.|
Limit on how many key to path entries are kept in memory during execution at a time to avoid having to recalculate the path on key lookups; default is 200.
|Algorithm used for creating paths; default is md5. Use crc32 on Windows to avoid path length issues.|
Issues with Microsoft Windows
If you are using a Windows OS, you may encounter an issue regarding long paths for cache directory name. The paths are long because Stash uses md5 to generate unique keys that are sanitized really quickly.
Solution is to change the hash algorithm used by Stash.
This configuration is only recommended for Windows users.
Note: You can also define the path where you want the cache files to be generated to be able to get even shorter system path for cache files.
FileSystem cache backend troubleshooting
By default, Stash Filesystem cache backend stores cache to a sub-folder named after the environment (
app/cache/prod). This can lead to the following issue: if different environments are used for operations, persistence cache (manipulating content, mostly) will be affected and cache can become inconsistent.
To prevent this, there are 2 solutions:
Always use the same environment, for web, command line, cronjobs etc.
2 . Share stash cache across environments
Either by using another Stash cache backend, or by setting Stash to use a shared cache folder that does not depend on the environment.
This will store stash cache to
APC & APCu
This cache backend is using shard memory with APC's user cache feature. As this is per server, it does not support multi server (. ) setups
Not supported because of following limitation
As APC(u) user cache is not shared between processes, it is not possible to clear the user cache from CLI, even if you set
apc.enable_cli to On. That is why publishing content from a command line script won't let you properly clear SPI Persistence cache.
Please also note that the default value for
apc.shm_size is 128MB. However, 256MB is recommended for APC to work properly. For more details please refer to the APC configuration manual.
|The time to live of the cache in seconds; default is 500 (8.3 minutes)|
|A namespace to prefix cache keys with to avoid key conflicts with other eZ Platform sites on same eZ Platform installation; default is |
Array of Memcached servers, with host/IP, port and weight
|A namespace to prefix cache keys with to avoid key conflicts with other eZ Platform sites on same eZ Platform installation (default is an empty string). |
Must be the same on all servers with the same installation. See Memcached prefix_key option *
|default true. See Memcached compression option *|
|default false. See Memcached libketama_compatible option *|
|default false. See Memcached buffer_writes option *|
|default false. See Memcached binary_protocol option*|
|default false. See Memcached no_block option *|
|default false. See Memcached tcp_nodelay option *|
|default 1000. See Memcached connection_timeout option *|
|default 0. See Memcached retry_timeout option *|
|default 0. See Memcached send_timeout option *|
default 0. See Memcached recv_timeout option *
|default 1000. See Memcached poll_timeout option *|
|default false. See Memcached cache_lookups option *|
|default 0. See PHP Memcached documentation * |
|See Memcached socket_send_size option *|
|See Memcached socket_recv_size option *|
|See Memcached serializer option *|
|See Memcached hash option *|
Specifies the method of distributing item keys to the servers. See Memcached distribution option *
* All settings except
servers are only available with memcached PHP extension. For more information on these settings and which version of php-memcached they are available in, see: http://php.net/Memcached
When using Memcache cache backend, you may use inMemory to reduce network traffic as long as you are aware of its limitations mentioned above.
Example with Memcache
Connection errors issue
If memcached does display connection errors when using the default (ascii) protocol, then switching to binary protocol (in the stash configuration and memcached daemon) should resolve the issue.
Using the internal cache service allows you to use an interface and to not have to care whether the system has been configured to place the cache in Memcached or on File system. And as eZ Platform requires that instances use a cluster-aware cache in Cluster setup, you can safely assume your cache is shared (and invalidated) across all web servers.
Interface will change in the future
Use unique vendor prefix for Cache key!
When reusing the cache service within your own code, it is very important to not conflict with the cache keys used by others. That is why the example of usage below starts with a unique "myApp" key. For the namespace of your own cache, you must do the same! So never clear cache using the cache service without your key specified, otherwise you'll clear all cache.
Get Cache service
Via Dependency injection
In your Symfony services configuration you can simply define that you require the "cache" service in your configuration like so:
The "cache" service is an instance of the following class:
Via Symfony Container
Like any other service, it is also possible to get the "cache" service via container like so:
Using the cache service
Example usage of the cache service:
For more info on usage, take a look at Stash's documentation.
Clearing Persistence cache
Persistence cache uses a separate Cache Pool decorator which by design prefixes cache keys with "ez_spi". Clearing persistence cache can thus be done in the following way:
Two parts of the permissions system are extensible from a programmatic perspective: Policies and Limitations
Policies: Custom Policies can be added for use in your own code, custom Policy example: comment/create
Limitations: You can extend existing Policies, and hence extend the permissions of the CMS, example could be adding a SubscriptionLimitation to content/read Policy