SiteAccess¶
Introduction¶
eZ Platform enables you to maintain multiple sites in one installation using a feature called SiteAccesses.
In short, a SiteAccess is a set of configuration settings that is used when you reach the site through a specific address. When the user visits the site, the system analyzes the URI and compares it to rules specified in the configuration. If it finds a set of fitting rules, this SiteAccess is used.
Settings defined per SiteAccess may include, among others, database, language or var
directory.
When that SiteAccess is used, they override the default configuration.
Selecting SiteAccesses¶
A SiteAccess is selected using one or more matchers – rules based on the uri or its parts. Example matching criteria are elements of the uri, host name (or its parts), port number, etc.
For detailed information on how SiteAccess matchers work, see SiteAccess Matching.
SiteAccesses use cases¶
Typical uses of a SiteAccess are:
- different language versions of the same site identified by a uri part; one SiteAccess for one language
- two different versions of a website: one SiteAccess with a public interface for visitors and one with a restricted interface for administrators
Enterprise
If you need to change between SiteAccesses in Page mode, do not use any functions in the page itself (for example, a language switcher). This may cause unexpected errors. Instead, switch between SiteAccesses using the SiteAccess bar above the page.
admin
SiteAccess¶
The back-office UI of eZ Platform is housed in a predefined admin
SiteAccess in admin_group
.
If you have a multisite setup with a separate back-office interface for each site, you need to create your own admin SiteAccesses and add them to this group. In cases where the sites are on separate databases they will need their own repository (including their own storage and search connection), var dir, cache pool, and ideally also separate Varnish/Fastly config for each site individually.
Configuring SiteAccesses¶
You configure SiteAccess in your config files (e.g. ezplatform.yml
) under the ezpublish.siteacess
keys.
Tip
If you encounter issues when configuring SiteAccess or want to check that system uses the correct value, use the following command:
bin/console [—-siteaccess=<SA>] ezplatform:debug:config-resolver <param.name>
For advanced users, the command can be used to test how different parameters work when configuring scopes.
The required elements of the configuration are:
list
¶
Lists all SiteAccesses in the installation.
default_siteaccess
¶
Identifies which SiteAccess will be used by default when no other is specified.
groups
(optional)¶
Collects SiteAccesses into groups that can be used later for configuration.
match
¶
The rule or set of rules by which SiteAccesses are matched. See SiteAccess matching for more information.
Enterprise
SiteAccess selection in Page Builder¶
To define which SiteAccesses are available in the submenu in Page Builder, use the following configuration.
siteaccess_list
is an array of SiteAccess identifiers:
1 2 3 4 5 6 7 8 |
|
If you are using multiple domains, list all domains for an admin SiteAccess under siteaccess_hosts
:
1 2 3 4 5 6 7 8 |
|
SiteAccess with separate admin domain
If an admin SiteAccess in your installation uses a different domain than the front SiteAccesses, be sure to use SSL (https protocol). Otherwise, you cannot preview content in Page Builder from the Back Office.
Settings per SiteAccess¶
Various system settings can be set per SiteAccess or SiteAccess group under the ezpublish.system
key. These settings include languages or the var
directory.
Multilanguage sites¶
A site has content in two languages: English and Norwegian. It has one URI per language: http://example.com/eng
and http://example.com/nor
. Uri parts of each language (eng, nor) are mapped to a SiteAccess, commonly named like the URI part: eng
, nor
. Using semantic configuration, each of these SiteAccesses can be assigned a prioritized list of languages it should display:
- The English site would display content in English and ignore Norwegian content;
- The Norwegian site would display content in Norwegian but also in English if it does not exist in Norwegian.
Such configuration would look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Note
A new SiteAccess is recognized by the system, but an Anonymous User will not have read access to it until it is explicitly given via the Admin > Roles panel. Without read access the Anonymous User will simply be directed to the default login page.
Defining SiteAccess name¶
In order to simplify the interface and create a better editorial experience, you can "hide"
the SiteAccess code and substitute it with a human-readable name of the website e.g. Tasteful Planet
, Page EN
.
List of interfaces where you can apply SiteAccess names:
-
Page Builder (SiteAccess switcher in the top navigation)
-
Content Preview (SiteAccess switcher in the dropdown menu)
-
Page creation modal window (when coming from Content Structure)
You can also translate SiteAccess names. Displayed names depend on the selected language of the administration interface.
To define translation you need to put them in YAML file with correct language code e.g. app/Resources/translations/ezplatform_siteaccess.en.yml
:
1 2 |
|
Scope¶
Configuration is resolved depending on scope. It gives the opportunity to define settings for a given SiteAccess, for instance like in the legacy INI override system.
The available scopes are:
global
- SiteAccess
- SiteAccess group
default
global
overrides all other scopes.
If global
is not defined, the configuration then tries to match a SiteAccess, and then a SiteAccess group.
Finally, if no other scope is matched, default
is applied.
In short: if you want a match that always applies, regardless of SiteAccesses, use global
.
To define a fallback, use default
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Be aware that the default
scope concerns both back and front views.
For example, the following configuration defines both the front template for articles
and the template used in the Back Office, unless other templates are configured for specific a SiteAccess or SiteAccess group:
1 2 3 4 5 6 7 8 9 |
|
Note that you should avoid defining a setting twice within the same scope, as this will cause a silent failure.
This mechanism is not limited to eZ Platform internal settings (the ezsettings
namespace) and is applicable for specific needs (bundle-related, project-related, etc.).
Always prefer semantic configuration especially for internal eZ settings. Manually editing internal eZ settings is possible, but at your own risk, as unexpected behavior can occur.
Cross-SiteAccess links¶
When using the multisite feature, it is sometimes useful to be able to generate cross-links between different sites within one installation. This allows you to link different resources referenced in the same content repository, but configured independently with different tree roots.
1 2 3 4 5 6 |
|
See ez_urlalias for more information about linking to a Location.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Important
As SiteAccess matchers can involve hosts and ports, it is highly recommended to generate cross-SiteAccess links in an absolute form (e.g. using url()
Twig helper).
Troubleshooting¶
- The first matcher succeeding always wins, so be careful when using catch-all matchers like
URIElement
. - If the passed SiteAccess name is not valid, an
InvalidArgumentException
will be thrown. - If the matcher used to match the provided SiteAccess doesn't implement
VersatileMatcher
, the link will be generated for the current SiteAccess. - When using
Compound\LogicalAnd
, all inner matchers must match. If at least one matcher doesn't implementVersatileMatcher
, it will fail. - When using
Compound\LogicalOr
, the first inner matcher succeeding will win.
Under the hood¶
To implement this feature, a new VersatileMatcher
was added to allow SiteAccess matchers to be able to reverse-match.
All existing matchers implement this new interface, except the regexp-based matchers which have been deprecated.
The SiteAccess router has been added a matchByName()
method to reflect this addition. Abstract URLGenerator and DefaultRouter
have been updated as well.
Note
SiteAccess router public methods have also been extracted to a new interface, SiteAccessRouterInterface
.
Navigating between SiteAccesses - limitations¶
There are two known limitations to moving between SiteAccesses in eZ Enterprise's Pages:
-
On a Page you can encounter a 404 error when clicking a relative link which points to a different SiteAccess (if the Content item being previewed does not exist in the previously used SiteAccess). This is because detecting SiteAccesses when navigating in preview is not functional yet. This is a known limitation that is awaiting resolution.
-
When navigating between SiteAccesses in the back office using the top bar, you are always redirected to the main page, not to the Content item you started from.
Injecting SiteAccess¶
SiteAccess is exposed in the Dependency Injection Container as the @ezpublish.siteaccess
service, so it can be injected into any custom service.
The @ezpublish.siteaccess
service, if needed, must be injected using setter injection. It comes from the fact that SiteAccess matching
is done in a kernel.request
event listener, so when injected into a constructor, it might not be initialized properly.
To ensure proper contract, the eZ\Publish\Core\MVC\Symfony\SiteAccess\SiteAccessAware
interface can be implemented on a custom service.
Example
Let's define a simple service which depends on the Repository's ContentService and the current SiteAccess.
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Exposing SiteAccess-aware configuration for your bundle¶
Symfony Config component makes it possible to define semantic configuration, exposed to the end developer.
This configuration is validated by rules you define, e.g. validating type (string, array, integer, boolean, etc.).
Usually, once validated and processed, this semantic configuration is then mapped to internal key/value parameters stored in the ServiceContainer
.
eZ Platform uses this for its core configuration, but adds another configuration level, the SiteAccess. For each defined SiteAccess, you need to be able to use the same configuration tree in order to define SiteAccess-specific config.
These settings then need to be mapped to SiteAccess-aware internal parameters that you can retrieve via the ConfigResolver
.
For this, internal keys need to follow the format <namespace>.<scope>.<parameter_name>
, where:
namespace
is specific to your app or bundlescope
is the SiteAccess, SiteAccess group,default
orglobal
parameter_name
is the actual setting identifier
For more information on ConfigResolver, namespaces and scopes, see eZ Platform configuration basics.
The goal of this feature is to make it easy to implement a SiteAccess-aware semantic configuration and its mapping to internal config for any eZ Platform bundle developer.
Semantic configuration parsing¶
An abstract Configuration
class has been added, simplifying the way to add a SiteAccess settings tree like the following in ezplatform.yml
or config.yml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
The fully qualified name of the class is eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\SiteAccessAware\Configuration
.
All you have to do is to extend it and use $this->generateScopeBaseNode()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Note
Default name for the SiteAccess root node is system
, but you can customize it.
To do this, pass the name you want to use as a second argument of $this->generateScopeBaseNode()
.
Mapping to internal settings¶
Semantic configuration must always be mapped to internal key/value settings within the ServiceContainer
.
This is usually done in the DIC extension.
For SiteAccess-aware settings, new ConfigurationProcessor
and Contextualizer
classes have been introduced to ease the process.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
Tip
You can map simple settings by calling $processor->mapSetting()
, without having to call $processor->mapConfig()
with a callable.
1 2 |
|
Important
Always ensure you have defined and loaded default settings.
In @AcmeExampleBundle/Resources/config/default_settings.yml
:
1 2 3 4 5 6 7 8 |
|
Merging hash values between scopes¶
When you define a hash as semantic config, you sometimes don't want the SiteAccess settings to replace the default or group values,
but enrich them by appending new entries. This is possible by using $processor->mapConfigArray()
,
which needs to be called outside the closure (before or after), in order to be called only once.
Consider the following default config in default_settings.yml
:
1 2 3 4 5 6 7 |
|
And then this semantic config in ezplatform.yml
or config.yml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
What you want here is that keys defined for setting_a
are merged between default/group/SiteAccess, like this:
1 2 3 4 5 6 7 |
|
Merge from second level¶
In the example above, entries were merged in respect to the scope order of precedence. However, if you define the planets
key for siteaccess1
, it will completely override the default value since the merge process is done at only 1 level.
You can add another level by passing ContextualizerInterface::MERGE_FROM_SECOND_LEVEL
as an option (third argument) to $contextualizer->mapConfigArray()
.
In default_settings.yml
:
1 2 3 4 5 6 7 |
|
Semantic config (ezplatform.yml
/ config.yml
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Result of using ContextualizerInterface::MERGE_FROM_SECOND_LEVEL
option:
1 2 3 4 5 6 7 |
|
There is also another option, ContextualizerInterface::UNIQUE
,
to be used when you want to ensure your array setting has unique values. It will only work on normal arrays though, not hashes.
Limitations¶
A few limitations exist with this scope hash merge:
- Semantic setting name and internal name will be the same (like
foo_setting
in the examples above). - Applicable to first level semantic parameter only (i.e. settings right under the SiteAccess name).
- Merge is not recursive. Only second level merge is possible by using
ContextualizerInterface::MERGE_FROM_SECOND_LEVEL
option.
Dedicated mapper object¶
Instead of passing a callable to $processor->mapConfig()
, an instance of eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\SiteAccessAware\ConfigurationMapperInterface
can be passed.
This can be useful if you have a lot of configuration to map and don't want to pollute your DIC extension class (better for maintenance).
Merging hash values between scopes¶
As specified above, $contextualizer->mapConfigArray()
is not to be used within the scope loop, like for simple values.
When using a closure/callable, you usually call it before or after $processor->mapConfig()
.
For mapper objects, a dedicated interface can be used: HookableConfigurationMapperInterface
,
which defines 2 methods: preMap()
and postMap()
.