CakePHP: Smarter links
The Problem
There's a couple of things I wish were present in CakePHP's excellent HtmlHelper.
- Links should automatically add a class to themselves when they are a) pointing to a resource in the same controller and b) pointing to themselves.
- Able to show/hide themselves.
Why is #1 important? Imagine a primary navigation that runs across the top of a page:
[Home] [Articles] [About]
If the links knew what section they pointed to you could add CSS rules to highlight the homepage link when the user was on the homepage, the Article link when the user was on *any* page handled by the ArticleController, etc.
And #2? If you could easily toggle their visibility you could for example, only show edit links to users with edit privileges.
The Solution
Enter the LinkHelper. This helper has only one method (link) which does all the work we need:
(note, minor update to handle urls passed as an array)
app/views/helpers/link.php
class LinkHelper extends AppHelper { var $helpers = array( "Html" ); function link($title, $url = null, $display = true, $htmlAttributes = array(), $confirmMessage = false, $escapeTitle = true) { if (!$display) { // do not display this link return ""; } else { // display the link // parse the current url into its components $here = Router::parse($this->params['url']['url']); // parse the destination url into its components if (is_array($url)) { $destination = $url; } else { $destination = Router::parse($url); } if (!isset($destination['controller'])) { $destination['controller'] = $this->params['controller']; } $class = ""; if ($here['controller'] == $destination['controller']) { // link is to another action within this controller $class .= " current_controller"; if ($here['action'] == $destination['action']) { // link is to the current action in this controller $class .= " current_action"; } if (isset($htmlAttributes['class'])) { // we already have a class attribute, append our classes $htmlAttributes['class'] .= $class; } else { // class not set, add ours $htmlAttributes['class'] = trim($class); } } // build the link $link = $this->Html->link($title, $url, $htmlAttributes, $confirmMessage, $escapeTitle); // return the link return $this->output($link); } } }
What Is It Doing?
Firstly, its checks the $display parameter. If it's false, then it returns nothing.
Why is this useful? It means you can attach a rule to your links to determine if they should be rendered or not:
<?php echo $link-link("Edit this article", "/articles/edit/1", $is_admin) ?>
The link will only be visible when $is_admin is true. $is_admin is a view variable I set in my app's as part of the authentication process to indicate whether or not the current user has admin privileges.
You can embed other logic to show/hide the link too:
<?php echo $link-link("Edit this article", "/articles/edit/1", ($article['Article']['user_id'] == $auth_user['User']['id'])) ?>
The link will only be visible when the current user is the author of the article.
Secondly, the method checks if the link points to a page handled by the current controller. If it does, it appends "current_controller" to the class of the link.
This is useful for those primary nav links. The current link will have a class of "current_controller" and can be styled differently to the others (very handy for tabs!)
<ul> <li><?echo $link->link("Home", "/") ?></li> <li><?echo $link->link("Articles", "/articles/" ?></li> <li><?echo $link->link("About", "/about" ?></li> </ul>
Thirdly, the method checks if the link points to the current action of the current controller. If it does, it appends "current_action" to the class of the link.


Comments
Thanks for the correction
Thanks for the correction Chris :-)
you
you mean:
app/views/helpers/link.php ??
home page
seems it does not work when link is '/'
Hey thanks, This is an
Hey thanks,
This is an great helper.......
Thanks a lot..................
A minor tweak...
Updated the helper to handle urls passed as array("controller"=>"foo", "action"=>"bar")
Post new comment