Yii Framework Forum: Auto Breadcrumbs - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Auto Breadcrumbs A widget that automatically manages breadcrumbs Rate Topic: ****- 5 Votes

#1 User is offline   nickelstar 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 04-June 09

Posted 11 August 2009 - 08:04 PM

Starting from the Cookbook Breadcrumb example, I modified that by adding the following features:
  • Automatically tracks a user history since visiting the homepage. You no longer need to establish the bread crumb list for every view.
  • The breadcrumb name can either be set from either the page title or via a crumb title property.
  • The widget is established in the main layout view. So you don't need to put the widget in every view. Just set it in the main layout once, and you'll have breadcrumbs on every page.
  • Will truncate the breadcrumb list if it gets too long.
  • You can exclude certain pages (like the Login page) from showing up in the breadcrumb list.


I've only been using Yii for a couple of days, so there might be ways to improve this. Please feel free to share your comments. Enjoy!

components/BreadCrumb.php:
<?php
class BreadCrumb extends CWidget {

    public $crumbs = array();
    public $newCrumb =array();
    public $delimiter = ' &rarr ';
    public $hideCrumbsOnHome = true;
    public $firstCrumb = array('Home' => array('name' => 'Home', 'url' => array('site/index')));
    public $excludeCrumbs = array('Login');
    public $crumbs2Show = 3;
    public $truncatedCrumb = array('Truncated' => array('name' => '...'));

    public function run() {

        // Breadcrumbs are a way back to to the homepage so dump
        // the crumbs if we find ourselves back on the homepage
        $homepageRoutes = array('/index.php','/site/index','/');
        if ( in_array($this->newCrumb['url'][0], $homepageRoutes)) {
            unset ($_SESSION['crumbs']);

            // If desired, don't show the lone Home crumb on
            // the homepage
            if ($this->hideCrumbsOnHome) {
                return;
            }
        }

        // Place the homepgage anchor crumb in the first position
        $this->crumbs = $this->firstCrumb;

        // Some pages, such as Login, we don't want in the list, so
        // let's exclude them
        if ( !in_array($this->newCrumb['name'], $this->excludeCrumbs)) {


            $newCrumbKey = $this->newCrumb['name'];

            // If we have an existing crumb list, check to see whether
            // the new crumb is already in the list. If so, dump all the
            // crumbs from that crumb position to the end of the list. The
            // purpose of this is to keep the list clean of duplicates.
            if ( sizeof($_SESSION['crumbs']) > 0 ) {
                if ( array_key_exists($newCrumbKey, $_SESSION['crumbs'])) {

                    $offset = $this->array_offset($_SESSION['crumbs'], $newCrumbKey);
                    $_SESSION['crumbs'] = array_slice( $_SESSION['crumbs'], 0, $offset, true);

                }
            }

            // Finally add the new crumb to the end of the list
            $_SESSION['crumbs'][$newCrumbKey]=$this->newCrumb;

            // If we have more crumbs than we want to display, we'll evict the
            // oldest crumbs from the list. Plus we'll show a truncated crumb
            // so the user has a visual indicator that we are truncating.
            if (sizeof($_SESSION['crumbs']) > $this->crumbs2Show ) {
                array_shift($_SESSION['crumbs']) ;
                $this->crumbs = array_merge($this->crumbs, $this->truncatedCrumb);
            }
        }

        // Ok, we've build the crumb list prefix with the Home crumb and possibly
        // the Truncated crumb. Now lets add the user's crumbs.
        if ( sizeof($_SESSION['crumbs']) > 0 ) {
            $this->crumbs = array_merge($this->crumbs, $_SESSION['crumbs']);
        }

        // display!
        $this->render('breadCrumb');
    }

    /**
     * Find the integer position of the offset key in the array
     * @param array $array
     * @param string $offset_key
     * @return int
     */
    public function array_offset($array, $offset_key) {
        $offset = 0;
        foreach($array as $key=>$val) {
            if($key == $offset_key)
                return $offset;
            $offset++;
        }
        return -1;
    }
}
?>


components/views/breadCrumb.php:
<div id="breadCrumb">
    <?php

    $lastCrumb = array_pop($this->crumbs);
    
    foreach($this->crumbs as $crumb) {
        
        if(isset($crumb['url']) && !$isLastCrumb) {
            echo CHtml::link($crumb['name'], $crumb['url']);
        } else {
            echo $crumb['name'];
        }

        echo $this->delimiter;

    }
    echo $lastCrumb['name'];
    ?>
</div>


views/layouts/main.php
Note: You can set the breadcrumb title from one of two properties: either the page title property built into CControler or by a bread crumb title property that you will need to add into the relevant controller. Here's the steps needed to handle each scenario:

  • pageTitle:
    • In the controller actions, set the page title before rendering like so: $this->setPageTitle('Product #1022 Blue Bag with Shoulder Strap')



  • crumbTitle: Sometimes, you want the breadcrumb to be shorter or different than the page title. Setting this property will allow for that.
    • Add the crumbTitle property to the controller class like so: public $crumbTitle;
    • In the controller's actions, set the crumbTitle like so: $this->crumbTitle = 'Product #1022'


<div id="breadcrumbs">
<?php $this->widget('application.components.BreadCrumb', array(
  'newCrumb' =>
    array('name' => isset($this->crumbTitle)?$this->crumbTitle:$this->getPageTitle(), 'url' => array($_SERVER['REQUEST_URI']))
)); ?>
</div>

0

#2 User is offline   DarkNSF 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 287
  • Joined: 12-November 08
  • Location:Palm Bay, Florida

Posted 17 August 2009 - 09:03 PM

cool! this is much better than manually creating each breadcrumb.

what i think would be more elegant though is if the web of views was defined somewhere (if it supported wildcards like the url manager)
0

#3 User is offline   Rajesh 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 21-August 09

Posted 24 August 2009 - 01:27 PM

I believe some kind of variables and methods are missing on the documentation side, as while running the script, I am getting error related to
$_SESSION['crumbs']
and
$isLastCrumb
.
0

#4 User is offline   idle sign 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 56
  • Joined: 18-September 09
  • Location:Novosibirsk, Russia

Posted 22 September 2009 - 02:38 AM

I've made some fixes to nickelstar's code.

These are:
  • Fixed undefined variables (see Rajesh post).
  • Fixed 'UrlManager->urlSuffix' duplication issue when 'urlSuffix' is supplied.
  • First (home) breadcrumb now points to 'UrlManager->baseUrl' when is url is not supplied.
  • Introduced new property 'firstCrumbName' - easy way to set first crumb link text (see widget init example below).


Widget init example (eg. for views/layouts/main.php)
<div id="breadcrumbs">
    <?php
    $this->widget('application.components.BreadCrumb', array(
      'firstCrumbName' => 'The Beginning',
      'newCrumb' =>
	array(
	    'name' => isset($this->crumbTitle)?$this->crumbTitle:$this->getPageTitle(),
	    'url' => array(Yii::app()->getRequest()->requestUri),
	    )
    )); ?>
</div>


There are still many places in the code to improve ;)

Attached File(s)


1

#5 User is offline   Backslider 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 363
  • Joined: 23-July 09

Posted 08 October 2009 - 06:12 PM

The breadcrumb breaks if the application is in a sub-directory:

index.php?r=subdirectory/index.php?r=admin

rather than:

index.php?r=admin
We were all once expert at....... nothing.

yii-language-behavior

My Blog
0

#6 User is offline   AngĂ©llica Cardozo 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 137
  • Joined: 11-March 09

Posted 19 October 2009 - 10:57 AM

Yeah, it is breaking when creating Url in a subdirectory.

{ trying to fix it }
0

#7 User is offline   PeRoChAk 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 579
  • Joined: 26-November 10
  • Location:Lahore, Pakistan

Posted 29 December 2010 - 06:10 AM

Getting the same error as rajash
Cheers
Perochak
Web Design - Logo Design - Application Development

My Blog | Forums Comparison
0

#8 User is offline   PeRoChAk 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 579
  • Joined: 26-November 10
  • Location:Lahore, Pakistan

Posted 30 December 2010 - 03:34 AM

The Issue of undefined variables such as $_SESSION can be resolved by declaring a local variable of type array to store the data.

I have done it as
<?php
class BreadCrumb extends CWidget {

    public $crumbs = array();
    public $newCrumb = array();
    public $delimiter = ' &rarr; ';
    public $hideCrumbsOnHome = true;
    public $firstCrumbName = false;
    public $firstCrumb = array('Home' => array('name' => 'Home', 'url' => array()));
    public $excludeCrumbs = array('Login');
    public $crumbs2Show = 4;
    public $truncatedCrumb = array('Truncated' => array('name' => '…'));


    public function run() {
	$session_crumb=array();
	// if home url is not supplied, use application base url
	if (count($this->firstCrumb['Home']['url'])==0)
	    $this->firstCrumb['Home']['url'] = Yii::app()->UrlManager->baseUrl."/";

	if ($this->firstCrumbName) $this->firstCrumb['Home']['name']=$this->firstCrumbName;

        // Breadcrumbs are a way back to to the homepage so dump
        // the crumbs if we find ourselves back on the homepage
        $homepageRoutes = array('/index.php', '/'.Yii::app()->defaultController.'/list', '/');
	
        if ( in_array($this->newCrumb['url'][0], $homepageRoutes)) {
            unset ($session_crumb['crumbs']);

            // If desired, don't show the lone Home crumb on
            // the homepage
            if ($this->hideCrumbsOnHome) {
                return;
            }
        }

        // Place the homepgage anchor crumb in the first position
        $this->crumbs = $this->firstCrumb;

        // Some pages, such as Login, we don't want in the list, so
        // let's exclude them
        if ( !in_array($this->newCrumb['name'], $this->excludeCrumbs)) {

            $newCrumbKey = $this->newCrumb['name'];

	    if (!key_exists('crumbs', $session_crumb)) $session_crumb['crumbs'] = array();

            // If we have an existing crumb list, check to see whether
            // the new crumb is already in the list. If so, dump all the
            // crumbs from that crumb position to the end of the list. The
            // purpose of this is to keep the list clean of duplicates.
            if ( sizeof($session_crumb['crumbs']) > 0 ) {
                if ( array_key_exists($newCrumbKey, $session_crumb['crumbs'])) {

                    $offset = $this->array_offset($session_crumb['crumbs'], $newCrumbKey);
                    $session_crumb['crumbs'] = array_slice( $session_crumb['crumbs'], 0, $offset, true);

                }
            }

	    // Handle UrlManager->urlSuffix case
	    $this->newCrumb['url'][0] = rtrim($this->newCrumb['url'][0], Yii::app()->UrlManager->urlSuffix);
            // Finally add the new crumb to the end of the list
            $session_crumb['crumbs'][$newCrumbKey]=$this->newCrumb;

            // If we have more crumbs than we want to display, we'll evict the
            // oldest crumbs from the list. Plus we'll show a truncated crumb
            // so the user has a visual indicator that we are truncating.
            if (sizeof($session_crumb['crumbs']) > $this->crumbs2Show ) {
                array_shift($session_crumb['crumbs']) ;
                $this->crumbs = array_merge($this->crumbs, $this->truncatedCrumb);
            }
        }

        // Ok, we've build the crumb list prefix with the Home crumb and possibly
        // the Truncated crumb. Now lets add the user's crumbs.
        if ( sizeof($session_crumb['crumbs']) > 0 ) {
            $this->crumbs = array_merge($this->crumbs, $session_crumb['crumbs']);
        }

        // display!
        $this->render('BreadCrumb');
    }

    /**
     * Find the integer position of the offset key in the array
     * @param array $array
     * @param string $offset_key
     * @return int
     */
    public function array_offset($array, $offset_key) {
        $offset = 0;
        foreach($array as $key=>$val) {
            if($key == $offset_key)
                return $offset;
            $offset++;
        }
        return -1;
    }
}
?>

Cheers
Perochak
Web Design - Logo Design - Application Development

My Blog | Forums Comparison
0

#9 User is offline   kellan4459 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 04-November 11

Posted 20 December 2011 - 10:22 AM

Have any of you had an issue where the array resets each time you navigate to a new page?

For example I am getting

Home -> Page1

Home -> Page2

Home -> Page3

instead of

Home -> Page1 -> Page2 -> Page3

I am using the last set of code from PeRoChAk and the display view/BreadCrumb.php from the original post of nickelstar
0

#10 User is offline   Jaggi 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 90
  • Joined: 05-September 11

Posted 20 December 2011 - 11:46 AM

View Postkellan4459, on 20 December 2011 - 10:22 AM, said:

Have any of you had an issue where the array resets each time you navigate to a new page?

For example I am getting

Home -> Page1

Home -> Page2

Home -> Page3

instead of

Home -> Page1 -> Page2 -> Page3

I am using the last set of code from PeRoChAk and the display view/BreadCrumb.php from the original post of nickelstar


Breadcrumbs provide a trail back to the entry point to your site not a history of where the user has been. Therefore what you're experiencing above is working as it should do. You should use pagination to get around the pages not the breadcrumbs.
See my development site @ www.CodeTheInter.net (BETA)

Posted Image Posted Image

Quote

If you make it idiot proof, they'll build a better idiot
0

#11 User is offline   kellan4459 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 04-November 11

Posted 20 December 2011 - 12:15 PM

View PostJaggi, on 20 December 2011 - 11:46 AM, said:

Breadcrumbs provide a trail back to the entry point to your site not a history of where the user has been. Therefore what you're experiencing above is working as it should do. You should use pagination to get around the pages not the breadcrumbs.


My understanding from the original posters functionality this would do what I was looking for since they stated:

Quote

Automatically tracks a user history since visiting the homepage. You no longer need to establish the bread crumb list for every view.


So if when a user enters the site and clicks a link to currentSeason then clicks a link to currentPlayers then clicks a link to currentPlayers/edit/5

If I want the user to have the history

Home -> Current Season -> Current Players -> Edit Player 5

what is the proper widget/extension to use? My searches turned up the dynamic breadcrumb and when I used the original post from nickelstar it functioned similarly to what I expected but there appeared to be some problems that were worked out so I changed to PeRoChAk's code which functions differently.
0

#12 User is offline   edulises 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 17-August 13

Posted 20 August 2013 - 02:26 PM

kellan4459 could you post your code, to understand what you mean?
Thanks
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users