shazarre
shazarre

Reputation: 225

Breadcrumbs logic in MVC applications

Where should a breadcrumbs path be declared (in other words, in which letter of MVC)? So far I've been declaring it in Controllers, but I've recently started to work with CakePHP, where it is all made in Views and it surprised me.

Upvotes: 3

Views: 3954

Answers (5)

Jimbo
Jimbo

Reputation: 26624

I'm going to throw an answer out here, because there's a lot of confusion about what should and shouldn't be done with breadcrumbs.

The Model

The Model is a layer that contains your business logic consisting of domain objects, data mappers and services. You can read more about the model here.

The Controller

Remember: fat model, skinny controllers. Your controller / method is accessed from your routing mechanism. Once you're in the controller, you want to get your model object, perform whatever logic is required in the model, have the result of this returned to a variable in your controller, and then you use this to display data in your view.

The Breadcrumbs

That being said, your breadcrumbs need different parts to work. Let's think about this:

  • They need the current page
  • They need a list of pages
  • They (may) need a custom "class=current" added

Breaking those down:

  • In my framework, the current controller is also the page name (login controller maps to /login). So, we already have the current page.
  • The list of pages.
    • If your parent/child relationship of the pages are tied directly to the datamodel, then in your controller you pull the list of pages from the model. So use the model if the breadcrumbs can be automatically generated.
    • If the framework you're using allows breadcrumbs created entirely by user choice, then you are just choosing what to put in the breadcrumbs manually. Either way, you state your breadcrumbs in the controller, and if you need to get them from somewhere, use the model.
  • Finally, the "class=current". Although you shouldn't really contain significant 'logic' in your view, small things like loops or if statements are pretty standard. Here, you would check your breadcrumbs for the title equalling the current controller name (passed through as a variable to the view), and add a class=current if found.

Code Example

Note: untested

/**
 * So we're in the home controller, and index action
 *
 * @route localhost/home or localhost/home/index
 * (depending on .htaccess, routing mechanism etc)
 */
class Home extends Controller
{
    public function index()
    {
        // Get current class name, so we have the current page
        $class = __CLASS__;

        // Let's say the page heirachy is tied to the model, so get pages for current method, or however you want to implement it
        $pages = $model->getPages($class);

        // So the TEMPLATE handles the breadcrumbs creation, and the controller passes it the data that it needs, retrieved from the model
        // (new Template) is PHP 5.4's constructor dereferencing, also included is some lovely method chaining
        // setBreadcrumbs() would assign variables to the view
        // Render would do just that
        (new Template)->setBreadcrumbs($currentPage, $pages)->render();
    }
}

And now, the view... note, I use PHP 5.4, so I can use short echos...

<body>
    <?php foreach($breadcrumbs as $b) { ?>
        <li <?=($b['current'])?'class="current"':''?>>
            <a href="<?=$b['page']['url']?>">
                <?=$b['page']['title']?>
            </a>
        </li>
    <?php } ?>
</body>

And that's how I would do it. Some of this is down to personal preference, but I hope this shows one way of doing it and is at least a little useful.

I actually came across this answer googling "php mvc breadcrumbs", and writing out my brain has really helped me to figure this out too. So thanks!

Upvotes: 4

Aziz
Aziz

Reputation: 917

$this->Html->addCrumb('Home', '/pages/home');
$this->Html->addCrumb('Contacts', '/pages/contacts');

echo $this->Html->getCrumbs('&raquo;', 'StartText');

Upvotes: 0

bsboris
bsboris

Reputation: 639

Whenever you see words "logic" and "view" together you should start worrying. My vote is for Controller because breadcrumbs is typical example of application-level logic, so putting it to the view violates MVC in my opinion.

Upvotes: 1

tvanfosson
tvanfosson

Reputation: 532615

IMO, the breadcrumb relates to the set of controller actions taken to get to the current page or the action's place in the hierarchy of the site, depending on your interpretation. From that perspective, the controller seems the natural place to construct the data for it, though the rendering should occur in the view. In order for it to be completely generated in the view, you would need to either expose details about what controller action is being invoked by the view or have a fixed view-per-action model so that the breadcrumb for each could be precalculated. Moving the logic for computing the breadcrumb to the view itself seems to violate the separation of concerns in MVC and may preclude reusing views for different actions, which would violate DRY>

In my opinion, generating data for the breadcrumb is a cross-cutting concern in the controller, i.e., you have some shared code that runs regardless of the action that uses the url to construct the breadcrumb data. There is also some shared view code that takes the controller-supplied data and renders it consistent with the design.

Note that I'm speaking from a purely architectural perspective. I'm not familiar enough with CakePHP (or other PHP frameworks, for that matter) to even judge whether your observation about it is correct. From a pattern perspective, putting it in the controller seems like the right thing to do. In a given implementation, though, it might make sense to violate the pattern.

Upvotes: 0

Josh K
Josh K

Reputation: 28893

Breadcrumbs should be in the controller. I use CodeIgniter and do something like

$data['breadcrumb'][0] = array("title" => "Home", "alt" => "Home Page", "path" => "home/");
$data['breadcrumb'][1] = array("title" => "About", "alt" => "About Me", "path" => "home/about");

And then in the view loop through and display them as a list.

<ul class="breadcrumbs">
foreach($breadcrumb as $b)
{
    ?>
        <li><a href="<?php echo base_url(); ?>index.php/<?php echo $b['path'];?>" alt="<?php echo $b['alt']; ?>"><?php echo $b['title']; ?></a></li>
    <?php
}
</ul>

You can then also declare simple things like classes, current pages, etc. The only downside is you have to set the breadcrumbs in every page.

ALL logic should be in the controller. Access databases through the models, perform logic in the controller, and pass it to the view.

Simple stuff like

<?php echo ($loggedin)?"Logged in as" . $user->firstname:"Not logged in";?>

can be in the view. But you shouldn't be setting up complex flow patterns. Leave that to the controller. Views are cheap. You can have a half dozen slightly different views and no one will care. It's not like static HTML where you would have to maintain a half dozen pages.

Include common things in the views (like headers, footers, script files, javascript files, etc) and then let them be.

Upvotes: 0

Related Questions