Posts tagged with “oop”

CakePHP: Adding Dynamic Content to Layouts

For the past few months, I’ve had this lingering item on my TODO list to Learn CakePHP. When that item was added to the list, we had decided to use it as our default framework for building new apps at work and I wanted to at least be aware of its basic capabilities, techniques and toolkits. Unfortunately, I don’t get as much time as I’d like to put my head down and write code at work, so this item has been taunting me until this week when some time presented itself.

I come into this brand new to CakePHP, but as an experienced web and OOP developer. I have certain expectations of encapsulation, elegance and maintainability that I want to bring to my CakePHP project. As I run across scenarios where I don’t think that such elegance is obvious, I’ll document the solution I used here. Maybe someone else can benefit from my experience and maybe I can benefit from that of others.

The Project

Since I learn most effectively by doing, I needed a project. The project I chose was a rebuild of a site I did about a year ago; I was familiar with the needs as well as the things I would have liked to do differently, had there been enough time.

For the site I’m building, I have not only a header and a footer, but also a sidebar. The site has navigation menus in each of these areas of the template that I wanted to be data driven and several menu items are shared across menu locations. Not an uncommon need, to be sure, but I wasn’t sure how to handle it with CakePHP because layouts don’t have models – or controllers – of their own to access the data and this layout would be shared by every page in the site – I didn’t want to add the logic to retrieve and manipulate menu data in more than one place.

The Scenario

The scenario, then, is the need to place dynamic content within a layout. Without going into excruciating detail, a CakePHP layout is analogous to a template in a CMS. It’s the part of the page that is fixed and usually shared across multiple pages of a site. On robwilkerson.org, for example, the layout would include the header, the footer and the sidebar on the right. Everything else is the page content or, in CakePHP’s MVC-speak, the view template.

The Data

The backbone of a data driven solution, of course, is the database. For my menus problem, I created three tables: nav_menus, nav_menu_items and nav_menu_items_nav_menus following all of the conventions of CakePHP so that everything would work without any more effort than necessary. The last table, of course, is a linking table to identify which items exist on which menus. The many-to-many relationship it enables is what allows a single menu item to appear on more than one menu.

The Models & Controllers

With the database prepared, I needed to provide access from my application and this is where CakePHP and most other frameworks I’m familiar with really shine. Using CakePHP, I just “baked” models and controllers using the command line utility:

$ cd path/to/cake/console
$ ./cake bake model nav_menu
$ ./cake bake controller nav_menus
$ ./cake bake model nav_menu_items
$ ./cake bake controller nav_menu_items

That’s it. A few simple command line requests and I had all the files I needed. All that was left to get this scaffolded up was to define the associations between the models I’d just created. To do so, I opened each model file (located in app/models/) and added a single line of code to each. To app/models/nav_menu.php, I added the following:

public $hasAndBelongsToMany = array ( 'NavMenuItem' );

Similarly, I added the following to app/models/nav_menu_item.php:

public $hasAndBelongsToMany = array ( 'NavMenu' );

That’s all I needed to do to be able to create new menus and menu items. By requesting http://localhost/nav_menus/add, I was able to use CakePHP’s scaffolded interface to create new menus. Likewise, by accessing http://localhost/nav_menu_items/add, I could create new menu items and assign them to the appropriate menus.

Sharing the Logic

The non-obvious question in my mind was how do I get this dynamic data displayed on a layout? A layout doesn’t have its own controller and I sure has hell don’t want to have to tell every controller how to render my navigation. Inheritance to the rescue.

CakePHP’s controllers all extend the AppController class, so I dropped my menu logic there:

class AppController extends Controller {
   public $uses = array ( ‘NavMenu’ );

public function beforeRender() { /** * Populate and expose menu data */ $raw_menus = $this->NavMenu->find ( ‘all’ ); $menus = $this->NavMenu->unobfuscateMenus ( $raw_menus ); $this->set ( ‘nav_menus’, $menus ); } }

In my mind, this is perfectly reasonable since this logic really will be used on every single page request; there are no CPU cycles being wasted.

An Associative Recordset

If anyone’s wondering about the unobfuscateMenus() method, I created a custom method in my NavMenus model that would allow me to access and key on my menus as an associative array rather than as an indexed array. I have three menus: Primary, Secondary and (surprise!) Tertiary. By default, CakePHP exposes these as $nav_menus[ 0 ][‘Primary’], $nav_menus[ 1 ][‘Secondary’], etc. I wanted to be able to key on the menu name, though, so that in my layout, I had the ability to access the precise menu I wanted when I wanted it.

The unobfuscateMenus() method reorganizes the array slightly so that I can access $nav_menus[‘Primary’] when I want to display the primary menu without looping over all menus and testing for the menu name. This should become more clear in the code that renders the menu below.

With the code added to the AppController class, all of my controllers and, by extension, all of my layouts will have access to my menu data. Since I have several menus on my layout, I not only wanted to share the logic, but also the output.

Sharing the Output

Duplicating presentation code is almost as distasteful to me as duplicating business logic, so I created a navigation element that would accept my $nav_menus array and iterate over each item to create an unordered list. The menu array whose items will be displayed is passed to the element as the $menu variable.

<ul>
   <?php $i_item = 0; ?>
   <?php foreach ( $menu['items'] as $item ): ?>
   <?php
      $i_item++;
      $item_class = '';
      if ( $i_item  1 ) {
         $item_class = ' class="first"';
      }
      else if ( $i_item  count ( $menu['items'] ) ) {
         $item_class = ' class="last"';
      }
   ?>
   <li<?php echo $item_class; ?>>
      <a href="<?php echo $item['target_uri']; ?>" 
         title="<?php echo $item['description']; ?>"
         ><?php echo $item['title']; ?></a>
   </li>
   <?php endforeach; ?>
</ul>

Wiring It All Together

My logic, data and presentation code are all in place now, so the only thing left is to apply the context – the layout. In my layout markup, I included the following code to display my primary menu:

<?php echo $this->element (
      'navigation',
      array (
         'id'   => 'primary',
         'menu' => $nav_menus['PRIMARY']
      )
   );
?>

And for my secondary menu:

<?php echo
      $this->element (
      'navigation',
      array (
         'id'   => 'secondary',
         'menu' => $nav_menus['SECONDARY']
      )
   );
?>

Key Points

Here’s what I like about this solution, in no particular order:

  1. One database query. I have three menus and I certainly could have retrieved each menu individually. Whenever it’s feasible, though, I like to avoid querying the database. In my experience, the database is almost always the bottleneck for an application; the less I have to communicate with it, the better. With a little application logic (the unobfuscateMenus() method), I get all the benefits of three queries at the performance cost of just one.
  2. It will scale. If I need six navigation menus, all that’s required is a little more data. The code can handle the additional menus without any changes.
  3. There’s no waste. I’m very wary of dropping code in a super class, but in this case it works. The AppController class is loaded on every request and the logic it includes is used on every request. Symmetry.
  4. Encapsulation of presentation. Within the element, there’s no logic that isn’t used exclusively for presentation. Because I unobfuscated the menus array, I’m able to pass in only the menu that needs to be rendered by the element at the time it’s called.

Class Inheritance

Today, after returning from a weekend (largely) spent offline, I was catching up on some reading and ran across a column on PHPBuilder.com entitled Class Inheritance with PHP. Let me start with this disclaimer: I know nothing of PHPBuilder.com, its reputation or its editorial process, if any. Nonetheless, I was a little surprised by what I read.

Inheritance is a fundamental concept of OOP and, as the author correctly states, is one means of “simplifying and reducing instances of redundant code”. A vast oversimplification, I think, but not technically incorrect so I read on to this pseudo-example:

Consider a tree. A tree is made up of many parts, such as the roots that reside in the ground, the trunk, bark, branches, leaves, etc. Essentially inheritance is a connection between a child and its parent.

Reading that, I was stunned. I have to assume that this is an introductory article. First, because of its introductory subject matter and second, because it’s barely two pages long including example code. Is this really how folks new to OOP should be thinking about inheritance? I think not.

While inheritance is a connection between a child and its parent, what the author is actually depicting in the example is composition, not inheritance. The first clue to that should have been the use of the phrase “made up of many parts”. Inheritance represents an “is-a” relationship, yet the author is describing a “has-a” relationship. A more accurate representation, still using the tree metaphor, might state that there are many types of trees – oak, maple, evergreen, etc. Each of these types of tree share a good many attributes and behaviors, but differ in others. Even with these differences, an oak tree – and each of the others listed – is-a tree and can properly inherit shared attributes and behaviors from a generic tree.

I almost stopped there, but decided to read on. After all, there was nowhere to go but up, right? To be fair, the column did proceed in a generally upward direction, but I don’t think it clarified the concept of inheritance much. Not for OOP beginners, at least. The example focuses on a Car class that inherits from a Product class. Not inaccurate in that a car can certainly be a product, but surely there are better introductory examples that could have been used. Product is too generic and as a result the parent-child relationship defined is too ambiguous for a column introducing basic material. A better example, following the same metaphor, might have been to subclass Vehicle with Car, SportUtilityVehicle, MiniVan, etc. At least there’s a clear and commonly understood relationship between each class.

Even as introductory material – and maybe especially as introductory material – I’m surprised that this column saw the light of day. If PHPBuilder.com is unmoderated and unedited, then so be it, but it doesn’t appear that this is the case. This column, in its current form, does not provide an accurate depiction of the concept of inheritance. It’s simply misleading.