Logo ZenEngine Logo SourceForge.net ZenEngine
the lightweight CMS framework


# Building and walking the menu

The first service of ZenEngine is to provide a menu, so you don't have to edit each and every page each time you add, delete or move a page. The ZenEngine/Core package define the abstract ZenAbstractMenuMaker class, and the concrete ZenMenuManager and ZenMenuItem classes.

the menuMaker and the menuItems

The MenuMaker is responsible for building a menu. A menu is actually an associative array of keys and ZenMenuItems. A ZenMenuItem is mainly a data object that holds informations needed by the ZenMenuManager, the ZenContentManager and the docMaker objects to do their job. There is no concrete implementation of the MenuMaker class in the ZenEngine/Core package, because there are many ways to build a menu : from a file system hierarchy like ZenFSMenuMaker, or from a textual format file, or from a SQL Database, etc...

the menuManager

The menu built by the chosen MenuMaker implementation is passed to a ZenMenuManager object, that give access to the menu items (find, next, prev etc...). Note that the ZenEngine class act as a facade for some of the ZenMenuManager methods, and in most cases, you won't have to deal with the menuManager itself.

[New in version 0.0.6] In fact, most of the time, you'll only need to define how menu items and sections are to be displayed by tweaking the menuMaker's conf, and then call the ZenEngine->getPrettyMenu() method.

But, as there are many ways you may want to display the menu, you can also write your own 'printMenu' (or whatever you name it) function. This sure means more work, but this also means more control and more freedom. If you go that way, you may also write your own prettyPrinter class and use it instead of the default Core/ZenSimplePrettyPrinter class.

more about menuItems

Calls to the menuManager's navigation methods, be it directly or via the ZenEngine's facade methods, usually return a ZenMenuItem object. When it comes to printing your menu (if you go for a pretty customized use of ZenEngine...), you can retrieve the href and caption for this link with ZenMenuItem's getHRef() and getCaption() methods.

documents vs categories

A ZenMenuItem can represent a 'document' (content to show in a page) or a 'category', regrouping related documents. In this last case, the getHRef() method will return null, as there is no directly related content. the isDoc() method will tell you whether the menuItem is a document or a category.

Note that category may be nested (a category may have sub-categories). The getLevel() method will tell you about the 'nesting level' of the menuItem, zero meaning top level. You can use this information to display your menu in a hierarchical fashion. Note also that documents do not need to be in a category, they can be at top level.

configuration files

So how does the ZenEngine know which menuMaker implementation it must use ? The answer is in the main configuration file. This file is an ini-like file, and must contain the following entries :

  • menumaker_class=[the name of the menuMaker implementation class]
  • menumaker_inc=[the path to the php file containing that class]
  • menumaker_conf=[the path to an implementation specific conf file for the menuMaker]
For exemple, in this site's main conf file, those entries looks like this


# An implementation exemple : ZenFSMenuMaker

ZenFSMenuMaker, which as at this time the only implementation of the ZenAbstractMenuMaker interface, creates a menu from a file system hierarchy. While this might not be the smartiest solution, it has the advantage that the menu should always be in sync with the structure of the site.

Creating the menu

ZenFSMenuMaker creates the menu by recursively listing a specific data directory content. This directory is mentionnend in ZenFSMenumaker's conf file. For each file or sub directory in the the data directory that has an extension listed in the conf file, ZenFSMenuMaker creates a menu item and adds it to the menu (an associative array). Note that dotfiles and dotted directories won't be included.

Files names and menuItems

The expected syntax for files names in the data directory is

The expected syntax for sub-directories names in the data directory is
Note that subdirectories having an extension will be treated as files (they are in fact 'composed documents').
  • The caption for the menuItem is made by removing everything after the first dash (including the dash itself), and replacing underscores with spaces.
  • The key for this menuItem is made of the xxx part following the dash, where xxx is a numeric code. This code is used as a key in the menu, parents item's key being prepended joined by dots
  • If the file or directory has an extension known as a docType in the conf file, the menuItem will correspond to a document, and the menuItem's docType filed will be filled with the extension.
So a directory name like 'Documentation-002' would give 'Documentation' as caption and '002' as key, and a file name like 'About_this_document-001' for a file under the datadirectory/Documentation-002/ directory would have 'About this document' for caption and '002.001' for key.

Some more things...

The structure of a menu is an associative array of the keys and the corresponding menuItem objects. Once created, this array is sorted on keys (note: remember that keys are string).

One last point about the menuItems, and that will lead us to the next topic, is the docQueryData field of the ZenMenuItem class. This field holds content used by the docMaker associated with the menuItem's docType to retrieve the effective data. As theses informations are somewhat specific to the data storage mode and format, this structure of this field is a convention between the menuMaker and the docMaker. For exemple, with ZenFSMenuMaker and the ZenFS docMakers, this field is an array with the docType and the path of the file. For a SQL based system, it could be specific values for a SQL SELECT statement.