Working with symfony plugins : Breadcrumb

Symfony plugins are very good if you want to include a feature inside your application. Plugins allow developers to overwrite most of the code : actions, template, configuration and schema. But now, if you look down on plugin’s architecture there is no easy way to redefine breadcrumb from your application. Mainly because each applications use its own custom functions and symfony does not provide a standard way to build such feature.

Now the situation is when you include plugins in you application and want to include breadcrumb you end up by rewriting the plugins’s actions.class.php inside you application. And maybe write stuff like this :

public function executeMyAction($request)  
{  
    parent::executeMyAction($request);  

    yourBreadcrumbClass::getInstance()->add('your information here');  
}

Or maybe do something special with post and pre execute method. From my point of view this is bad, and totally nonsense.

So I come up with an alternative solution, where we don’t need to update any plugins file. The idea has been implemented in the swToolboxPlugin, but you can easily recreate this for your project.

The idea : centralize !

Just have one big class where all breadcrumb definitions are centralized in one place. Look odd ? maybe … but in fact this is time saving. Breadcrumb are parts of the SEO stuff, having one place to handle all breadcrumb will just help you to quickly fix issue or update them.

How to use it ?

In the layout.php file just place the breadcrumb component, this code will display the breadcrumb :

<?php include_component('swToolbox', 'displayBreadcrumb') ?>

How to define you breadcrumb ?

Copy the swBreadcrumb file from the plugin’s lib folder.

If you have a plugin’s module called swBlogPosts and a view action (display a blog post…), just create a ‘swBlogPosts_view’ method, and define the breadcrumb.

class swBreadcrumb extends baseswBreadcrumb {  

  public function swBlogPosts_view(sfAction $action)  
  {  
    self::add(__('breadcrumb_blog', null, 'global'), '@sw_blog\index', __('breadcrumb_blog', null, 'global'));  
    self::add($action->sw_blog_post->getTitle());  
  }  
}  

The swBreadcrumb::add method accepts 4 arguments :

  • The link text
  • The route name (optional)
  • The link title (optional)
  • The image (optional)

You can also redefine the view part by editing the _displayBreadcrumb.php file.

Let’s try to explain !

The breadcrumb component calls the swBreadcrumb::define method. The define method is very simple, the method just get the last action stack and test if a ModuleName_ActionName method exists. If so, the method should create the correct breadcrumb definition.

public function define()  
{  
  // get the last action stack  
  $action_stack = sfContext::getInstance()->getController()->getActionStack()->getLastEntry();  

  // retrieve the action and module name  
  $module_name = $action_stack->getModuleName();  
  $action_name = $action_stack->getActionName();  

  $method_name = $module_name.'_'.$action_name;  

  // test if the current instance of swBreadcrumb contains a method\_name  
  //  ie : swBlogPosts_view if module\_name = swBlogPost and action\_name = view  
  if(method_exists($this, $method_name))  
  {  
    // call the method with the last action instance so assignated variables are accessible  
    call_user_func(array($this, $method_name), $action_stack->getActionInstance());  
  }  
}

Conclusion

With this solution you can easily define the breadcrumb you want for your projects. And everything is centralized in one place.

PS : The state of the art solution will be to create a new event dispatcher that every plugin must define. So every plugin will be able to define a breadcrumb, free to the dev to use it or not.