As we all know, eZ Publish is very powerful, so much that there are probably some settings you didn’t even know existed and when you do find them, you feel like a luckiest man/woman alive. But, so much power can sometimes bring lots of headaches :)
One, relatively recent, headache I was having was when setting up host_uri siteaccess matching on one fairly large multilanguage & multisite eZ Publish installation. The installation has couple of databases and domains and many languages.
What is (host_uri) siteaccess matching anyway?
Every time you request a page from eZ Publish, it needs to decide what siteaccess to load based on your request. This process is called siteaccess matching. Most of the times, various parts of the request URI are used to decide which siteaccess to load. host_uri matching specifically allows you to match a combination of request host and first part of the request URI to one specific siteaccess. For example: http://www.example.com/fr/A-propos-de-nous will use www.example.com host and fr part of the URI to find the correct siteaccess to use. This rule would be defined in site.ini/[SiteAccessSettings]/HostUriMatchMapItems config array in the following way:
HostUriMatchMapItems[]=www.example.com;fr;french
which says: When the host is www.example.com and the URI starts with fr, load the siteaccess called french.
The other variant of the rule looks like this (notice that the second part of the value is empty):
HostUriMatchMapItems[]=www.example.com;;english
which says: If no other rules for www.example.com domain match the first part of the URI, load the siteaccess called english. Basically, this is a fallback rule.
The problem
On large multisite/multilanguage installations, host_uri matching array can quickly grow to 20+ lines of rules. The problem I was having was that no matter what I did, one of the rules did not function: Module “en” not found. The following is an excerpt from the rules:
MatchOrder=host_uri
HostUriMatchMapItems[]
HostUriMatchMapItems[]=www.example.com;;en
HostUriMatchMapItems[]=www.example.com;en;en
HostUriMatchMapItems[]=www.example.com;fr;fr
HostUriMatchMapItems[]=www.example.com;it;it
HostUriMatchMapItems[]=www.example.com;de;de
HostUriMatchMapItems[]=www.example.com;admin;admin
HostUriMatchMapItems[]=www.example.com;otheradmin;otheradmin
HostUriMatchMapItems[]=www.example.com;thirdadmin;thirdadmin
HostUriMatchMapItems[]=www.otherexample.com;;otheren
HostUriMatchMapItems[]=www.otherexample.com;fr;otherfr
HostUriMatchMapItems[]=otherexample.com;fr;otherfr
HostUriMatchMapItems[]=otherexample.com;;otheren
There were no syntax errors in the settings so I was losing my head over this for hours. Random reordering or array did nothing, apart giving the same Module not found error, but with different siteaccess. Left with nothing else to do, I went digging through kernel/classes/ezsiteaccess.php, which is responsible for matching.
The solution
After 2+ hours of digging, the solution was found. It turns out that order of array items does matter, but in very specific way. In every group of config values which have the same domain in HostUriMatchMapItems array, if there’s a config value with the empty second part, that specific config value needs to be the last one in that particular group of values. So, the solution to finally get the whole set of rules working was to reorder the mentioned array in the following way:
MatchOrder=host_uri
HostUriMatchMapItems[]
HostUriMatchMapItems[]=www.example.com;en;en
HostUriMatchMapItems[]=www.example.com;fr;fr
HostUriMatchMapItems[]=www.example.com;it;it
HostUriMatchMapItems[]=www.example.com;de;de
HostUriMatchMapItems[]=www.example.com;admin;admin
HostUriMatchMapItems[]=www.example.com;otheradmin;otheradmin
HostUriMatchMapItems[]=www.example.com;thirdadmin;thirdadmin
# Next rule is now moved to the end of group of values for www.example.com domain
HostUriMatchMapItems[]=www.example.com;;en
HostUriMatchMapItems[]=www.otherexample.com;fr;otherfr
# Next rule is now moved to the end of group of values for www.otherexample.com domain
HostUriMatchMapItems[]=www.otherexample.com;;otheren
HostUriMatchMapItems[]=otherexample.com;fr;otherfr
# Next rule is already at the end of group of values for otherexample.com domain
HostUriMatchMapItems[]=otherexample.com;;otheren
Later, I found exactly this solution in the last sentence of eZ Publish 4.4 release notes describing host_uri matching, which annoyed me even more because of the time lost which could’ve been used for more productive work. With this I hope at least some of you will be spared the headache I was having.