I have been using the visitor pattern to represent expression trees over the course of 10+ years on six large-scale projects in three programming languages, and I am very pleased with the outcome. I found a couple of things that made applying the pattern a lot easier:
Do not use overloads in the interface of the visitor
Put the type into the method name, i.e use
IExpressionVisitor {
void VisitPrimitive(IPrimitiveExpression expr);
void VisitComposite(ICompositeExpression expr);
}
rather than
IExpressionVisitor {
void Visit(IPrimitiveExpression expr);
void Visit(ICompositeExpression expr);
}
Add an "catch unknown" method to your visitor interface.
It would make it possible for users who cannot modify your code:
IExpressionVisitor {
void VisitPrimitive(IPrimitiveExpression expr);
void VisitComposite(ICompositeExpression expr);
void VisitExpression(IExpression expr);
};
This would let them build their own implementations of IExpression
and IVisitor
that "understands" their expressions by using run-time type information in the implementation of their catch-all VisitExpression
method.
Provide a default do-nothing implementation of IVisitor
interface
This would let users who need to deal with a subset of expression types build their visitors faster, and make their code immune to you adding more methods to IVisitor
. For example, writing a visitor that harvests all variable names from your expressions becomes an easy task, and the code will not break even if you add a bunch of new expression types to your IVisitor
later on.
PHP Dynamic and Recursive Menu System
When building the dynamic menu at my previous job, for our CMS, we had one class that dynamicly builds/prints the menu based on the menu object.
View output example of the code below
Since you're kind of new, I don't suggest making any overkill menu, but try to keep it as simple as possible.
I suggest making a class for the menu, where you send/store the menu array. This way you can make other objects unlock/lock different menu objects, or even send a sub-menu to that menu class (depending on how complex you want to make it).
This allows you to dynamicly build the menu as you run through the system code, and print the menu when your code is finished running. That way you can put the user based menu items in each section of the code, which handles that part.
For example, when running the system, make a function/method that checks the user access and for simple solutions, have hard-coded arrays with menu objects for each user access, or if going hardcore, build the menu arrays dynamicly. That's up to you.
<?php
// Let's create the child menu array for the "Home" menu structure
$home[] = array('TITLE' => 'Home 1',
'URL' => '/home-1-url-here',
'CSS_CLASS' => 'sub-menu',
'CHILDREN' => $home1Child);
$home[] = array('TITLE' => 'Home 2',
'URL' => '/home-2-url-here',
'CSS_CLASS' => 'sub-menu');
// Now we create the whole home array, with the children
$homeMenu = array('CSS_CLASS' => 'top-css-class',
'TITLE' => 'Home',
// If the top menu item is just a link, specify an URL
'URL' => '',
// Or if it has children pass them on
'CHILDREN' => $home);
// Let's create the child menu array for the "Gallery" menu structure
$gallery[] = array('TITLE' => 'Gallery 1',
'URL' => '/gallery-1-url-here',
'CSS_CLASS' => 'sub-menu');
$gallery2Child[] = array('TITLE' => 'Gallery 2.1',
'URL' => '/gallery-2.1-url-here',
'CSS_CLASS' => 'sub-menu-child');
$gallery2Child[] = array('TITLE' => 'Gallery 2.2',
'URL' => '/gallery-2.2-url-here',
'CSS_CLASS' => 'sub-menu-child');
$gallery[] = array('TITLE' => 'Gallery 2',
'URL' => '/gallery-2-url-here',
'CSS_CLASS' => 'sub-menu',
'CHILDREN' => $gallery2Child);
// Now we create the whole gallery array, with the children
$galleryMenu = array('CSS_CLASS' => 'top-css-class',
'TITLE' => 'Gallery',
// If the top menu item is just a link, specify an URL
'URL' => '',
// Or if it has children pass them on
'CHILDREN' => $gallery);
$menu = new menu;
// Store the menu items we want in the menu
$menu->storeItem($homeMenu);
$menu->storeItem($galleryMenu);
// Print the menu
echo $menu->buildMenu();
If you want to make sub-menus aswell, make the menu class work recursively.
class menu {
private $mainMenuClass = 'main-menu-class';
private $parentClass = 'parent-menu-class';
private $menu;
public function storeItem($menuItem, $parentClass = '') { // If no $parentClass is specified, pick the default one
// This stores the menu in an array
$this->menu[] = $menuItem;
}
public function buildMenu() {
// Let's break down the menu array, and start building it
$html = '<ul class="'. $this->mainMenuClass .'">'. PHP_EOL;
foreach($this->menu as $parentClass => $item) {
$html .= '<li class="'. $item['CSS_CLASS'] .'"><a href="'. $item['URL'] .'">'. $item['TITLE'] .'</a>'. PHP_EOL;
// Check if it's a recursive sub-menu (with children)
// Now we send the children array to the buildChildrenItems() method
$html .= $this->buildChildrenItems($item['CHILDREN']);
$html .= '</li>'. PHP_EOL;
}
$html .= '</ul>'. PHP_EOL;
return $html;
}
public function buildChildrenItems($menuSection) {
// Put the recursive logics here so we can keep looping
$html = '<ul class="'. $this->parentClass .'">'. PHP_EOL;
foreach($menuSection as $item) {
$html .= '<li class="'. $item['CSS_CLASS'] .'"><a href="'. $item['URL'] .'">'. $item['TITLE'] .'</a>'. PHP_EOL;
// Now here is where the recursive magic happends
// If the child item has even more children, call this method once again for those children
$html .= ( isset($item['CHILDREN']) && is_array($item['CHILDREN']) ) ? $this->buildChildrenItems($item['CHILDREN']) : '';
$html .= '</li>'. PHP_EOL;
}
$html .= '</ul>'. PHP_EOL;
return $html;
}
}
?>
From here you just design the menu as you want, using the CSS classes.
If you want to make it recursive (with dynamic sub-menus), then simply make the recursive logics before calling the buildChildrenItems() method. This is included in the code example above.
For more complex recursive menus, try these arrays.
$home1Child[] = array('TITLE' => 'Home 1.1',
'URL' => '/home-1.1-url-here',
'CSS_CLASS' => 'sub-menu-child');
$home121Child[] = array('TITLE' => 'Home 1.2.1',
'URL' => '/home-1.2.1-url-here',
'CSS_CLASS' => 'sub-menu-child');
$home121Child[] = array('TITLE' => 'Home 1.2.2',
'URL' => '/home-1.2.2-url-here',
'CSS_CLASS' => 'sub-menu-child');
$home1Child[] = array('TITLE' => 'Home 1.2',
'URL' => '/home-1.2-url-here',
'CSS_CLASS' => 'sub-menu-child',
'CHILDREN' => $home121Child);
$home1Child[] = array('TITLE' => 'Home 1.3',
'URL' => '/home-1.3-url-here',
'CSS_CLASS' => 'sub-menu-child');
$home[] = array('TITLE' => 'Home 1',
'URL' => '/home-1-url-here',
'CSS_CLASS' => 'sub-menu',
'CHILDREN' => $home1Child);
$home[] = array('TITLE' => 'Home 2',
'URL' => '/home-2-url-here',
'CSS_CLASS' => 'sub-menu');
$home[] = array('TITLE' => 'Home 3',
'URL' => '/home-3-url-here',
'CSS_CLASS' => 'sub-menu');
// Now we create the whole home array, with the children
$homeMenu = array('CSS_CLASS' => 'top-css-class',
'TITLE' => 'Home',
// If the top menu item is just a link, specify an URL
'URL' => '',
// Or if it has children pass them on
'CHILDREN' => $home);
// Let's create the child menu array for the "Gallery" menu structure
$gallery[] = array('TITLE' => 'Gallery 1',
'URL' => '/gallery-1-url-here',
'CSS_CLASS' => 'sub-menu');
$gallery2Child[] = array('TITLE' => 'Gallery 2.1',
'URL' => '/gallery-2.1-url-here',
'CSS_CLASS' => 'sub-menu-child');
$gallery2Child[] = array('TITLE' => 'Gallery 2.2',
'URL' => '/gallery-2.2-url-here',
'CSS_CLASS' => 'sub-menu-child');
$gallery[] = array('TITLE' => 'Gallery 2',
'URL' => '/gallery-2-url-here',
'CSS_CLASS' => 'sub-menu',
'CHILDREN' => $gallery2Child);
// Now we create the whole gallery array, with the children
$galleryMenu = array('CSS_CLASS' => 'top-css-class',
'TITLE' => 'Gallery',
// If the top menu item is just a link, specify an URL
'URL' => '',
// Or if it has children pass them on
'CHILDREN' => $gallery);
View output example of the code above
Finally, in the different classes for example, let's say the Gallery. Create the gallery menu array, check what kind of access the user has, and build it properly. Then you send the gallery menu array to the menu class, as shown above.
This concept is also good for future expansions, so when adding a new class/section on the website, let's say a guestbook. All the menu logics are built in that class and just sent to the dynamic menu class which builds it.
I do not recommend putting all the menu logics inside one big menu file, but as you run the system code, process each section and build the menu object as you go.
Hope this helps you on your way!
PS. If you have alot of user access types, and want to keep a clean code, put the menu arrays for each user access in seperate php files. (user_type_member.php or user_type_admin.php).
In the php code, where the arrays are written, just make a user type check, and call the according php file to load the array for that user.
switch($userType) {
default:
case 'visitor': include('user_type_visitor.php'); break;
case 'member': include('user_type_member.php'); break;
case 'admin': include('user_type_admin.php'); break;
}
Regards,
Andreas.
Best Answer
Proposed design:
You could use the command pattern:
optionAction()
(corresponds to theexecute()
method of the pattern).optionAction()
is overridden to define the actions that shall be executed for a specific command.main()
?), a reference to a receiver object is stored. That object will be used to execute the action later.SubmenuCommand
class, the instances of which will refer to a menu object that has a list of options (commands).main()
would somehow invoke the command corresponding to the toplevel menu. And this one would invoke the chosen commands.Variants of this design:
The menu objects could be constructed during initialization. Typically, you'd use the builder pattern to initialize each menu programatically. Then it could make sense to use
optionTitle()
.However, you could also load the menu from a configuration file. In this case, the
optionTitle()
would be useless: you'd read that title from the configuration file (with flexibility to customize the text, and even possibility to localize/translate the menus). In principle you'd do that in the the director of the builder, but if you want also to configure other commands, a factory method pattern could be considered as well.If you opt for the dynamically load of menus, there are a couple of delicate points to handle:
Wrap up:
Here a simplified class model that shows the general structure. I leave however the client, the invoker, the director and the builder out of this figure, as it depends very much on the rest of your application: