d13r/laravel-breadcrumbs

Don't understand how to make with nested set

schel4ok opened this issue · 6 comments

Summary of issue
Don't understand how to use breadcrumbs with nestedset

The complete error message, including file & line numbers
When I go to route links.index I get this error
Missing argument 1 for App\Http\Controllers\FileController::getIndex()

When I go to route links.cat page is rendered, but breadcrumbs are not showing

When I go to route links.item I get this error
ErrorException in RouteServiceProvider.php line 44: Object of class Illuminate\Routing\Route could not be converted to string

Software versions
Laravel Breadcrumbs: 3.0.1
Laravel: 5.1.43
PHP: 5.5.28

routes.php

Route::get('/', ['as' => 'home', 'uses' => 'HomeController@index']);
Route::get('about-us', ['as' => 'about', 'uses' => 'PageController@o_kompanii']);
Route::get('sitemap', ['as' => 'sitemap', 'uses' => 'CategoryController@sitemap']);
Route::get('contacts',  ['as' => 'contacts', 'uses' => 'PageController@contacts']);

Route::get('news', ['as' => 'news.index', 'uses' => 'NewsController@getIndex']);
Route::get('news/{newsitem}', ['as' => 'news.item', 'uses' => 'NewsController@getItem']);

Route::get('links', ['as' => 'links.index', 'uses' => 'FileController@getIndex']);
Route::get('links/{linkscat}', ['as' => 'links.cat', 'uses' => 'FileController@getCategory']);
Route::get('links/{cat}/{linksitem}', ['as' => 'links.item', 'uses' => 'FileController@getItem']);

Category model is nestedset.

Home         (instance of Category model level 0)
-News        (instance of Category model level 1)
--NewsItem1  (instance of News model)
--NewsItem2
--NewsItem3
...
-Links       (instance of Category model level 1)
--LinkItem1  (instance of Link model)
--LinkItem2
--LinkItem3
...
-Catalog     (instance of Category model level 1)
--Cat1       (instance of Category model level 2)
--Product1   (instance of Product model)
--Product2
--Product3
...
--Cat2       (instance of Category model level 2)
---Product1  (instance of Product model)
---Product2
---Product3
...
---Cat3      (instance of Category model level 3)
----Product1 (instance of Product model)
----Product2
----Product3
...
----Cat3      (instance of Category model level 4)
-----Product1 (instance of Product model)
-----Product2
-----Product3
...

breadcrumbs.php

use App\News;

// Home
Breadcrumbs::register('home', function($breadcrumbs)
{
    $breadcrumbs->push('Главная', route('home'));
});

// Home > About
Breadcrumbs::register('about', function($breadcrumbs)
{
    $breadcrumbs->parent('home');
    $breadcrumbs->push('О компании', route('about'));
});

// Home > News
Breadcrumbs::register('news.index', function($breadcrumbs) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push('Новости', route('news.index'));
});
// Home > News > Item
Breadcrumbs::register('news.item', function($breadcrumbs, $item) {
    $breadcrumbs->parent('news.index');
    $breadcrumbs->push($item->title, route('news.item'));
});
// Home > Links
Breadcrumbs::register('links.index', function($breadcrumbs) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push('Ссылки', route('links.index'));
});
// Home > Links > Cat > Item
Breadcrumbs::register('links.item', function($breadcrumbs, $cat, $item) {
    $breadcrumbs->parent('links.index');
    foreach ($category->ancestors as $ancestor) {
        $breadcrumbs->push($ancestor->title, route('links.cat'));
    }
    $breadcrumbs->push($item->title, route('links.item'));
});

HomeController.php
here I just get home category, which has sef=bez-kategorii

    public function index()
    {
        $category = Category::where('sef', '=', 'bez-kategorii')->first();
        return view('home')->withCategory($category);
    }

FileController.php

    public function getIndex($category)
    {
        $category = Category::where('type', '=', 'link')->first();
        $categories = $category->descendants()->orderBy('title', 'asc')->paginate(9);

        return view('links.index')->withCategory($category)
                      ->withCategories($categories);
    }

    public function getCategory($category)
    {
        $items = Link::where('category_id', $category->id)->paginate(20);
        $previous = $category->getPrevSibling();
        $next = $category->getNextSibling();

        return view('links.cat')->withCategory($category)
                    ->withItems($items)
                    ->withPrevious($previous)
                    ->withNext($next);
    }

    public function getItem($category, $item)
    {
            $previous = Link::where('id', '<', $item->id)->orderBy('id', 'desc')->first();
            $next = Link::where('id', '>', $item->id)->orderBy('id', 'asc')->first();

            return view('links.item')->withCategory($category)
                                     ->withItem($item)
                                     ->withPrevious($previous)
                                     ->withNext($next);
    }

RouteServiceProvider.php

<?php namespace App\Providers;

use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Route;
use App\News;
use App\Link;
use App\Category;

class RouteServiceProvider extends ServiceProvider
{
    public function boot(Router $router)
    {
        parent::boot($router);

        Route::bind('newsitem', function($item) {
            return News::whereSef($item)->firstOrFail();
        });

        Route::bind('links', function($cat) {
            return Category::whereSef($cat)->firstOrFail();
        });

        Route::bind('linkscat', function($cat) {
            return Category::whereSef($cat)->firstOrFail();
        });

        Route::bind('linksitem', function($cat, $item) {
            return Link::whereUrl('links/'.$cat.'/'.$item)->firstOrFail();
        });
    }
d13r commented

When I go to route links.index I get this error
Missing argument 1 for App\Http\Controllers\FileController::getIndex()

The action expects a parameter, but the route has none.

When I go to route links.cat page is rendered, but breadcrumbs are not showing

There is no breadcrumb with that name.

When I go to route links.item I get this error
ErrorException in RouteServiceProvider.php line 44: Object of class Illuminate\Routing\Route could not be converted to string

I'm not sure exactly but I suspect the binding for linksitem receives the router as the second parameter not a string.

ok I did simple with links.index and links.cat

routes.php

Route::get('links', ['as' => 'links.index', 'uses' => 'FileController@getIndex']);
Route::get('links/{linkscat}', ['as' => 'links.cat', 'uses' => 'FileController@getCategory']);
Route::get('links/{linkscat}/{linksitem}', ['as' => 'links.item', 'uses' => 'FileController@getItem']);

breadcrumbs.php

// Home > Links
Breadcrumbs::register('links.index', function($breadcrumbs) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push('Ссылки', route('links.index'));
});
// Home > Links > Cat
Breadcrumbs::register('links.cat', function($breadcrumbs, $category) {
    $breadcrumbs->parent('links.index');
    $breadcrumbs->push($category->title, route('links.cat'));
});
// Home > Links > Cat > Item
Breadcrumbs::register('links.item', function($breadcrumbs, $category, $item) {
    $breadcrumbs->parent('links.cat', $category);
    $breadcrumbs->push($item->title, route('links.item'));
});

but I still cannot understand ho to do breadcrumbs for the item.
Because I see that links.item needs to receive 2 objects $category and $item

Breadcrumbs::register('links.item', function($breadcrumbs, $category, $item) {
    $breadcrumbs->parent('links.cat', $category);
    $breadcrumbs->push($item->title, route('links.item'));
});

RouteServiceProvider.php

        Route::bind('links', function($cat) {
            return Category::whereSef($cat)->firstOrFail();
        });
        Route::bind('linkscat', function($cat) {
            return Category::whereSef($cat)->firstOrFail();
        });
        Route::bind('linksitem', function($item) {
            return Link::whereSef($item)->firstOrFail();
        });

now all routes are working well, but in route links.item breadcrumbs are not rendered good.
Home / Links / Category / Item

link to Category is showing like that http://site.dev/links/{linkscat}

Trying to understand what happens I was reading manual more and more, but I didn't find detailed description of additional parameters in breadcrumbs.

Though somehow I found solution of my question.

// Home > Links > Cat
Breadcrumbs::register('links.cat', function($breadcrumbs, $category) {
    $breadcrumbs->parent('links.index');
    $breadcrumbs->push($category->title, route('links.cat', $category->sef)); // here I must put $category->sef as a second parameter of route
});

// Home > Links > Cat > Item
Breadcrumbs::register('links.item', function($breadcrumbs, $category, $item) {
    $breadcrumbs->parent('links.cat', $category);  // here $category === $category->sef
    $breadcrumbs->push($item->title, route('links.item'));
});

But looking API reference for $breadcrumbs->parent($name)
There is nothing saying that you can put after the name second parameter, which will be URL and that parameter must be also mentioned in $breadcrumbs->push section of parent element.

d13r commented

But looking API reference for $breadcrumbs->parent($name)
There is nothing saying that you can put after the name second parameter

It's mentioned here in the API reference: http://laravel-breadcrumbs.davejamesmiller.com/en/latest/api.html#defining-breadcrumbs

$breadcrumbs->parent($name, $param1, ...)

And here in the tutorial: http://laravel-breadcrumbs.davejamesmiller.com/en/latest/defining.html#nested-categories

$breadcrumbs->parent('category', $category->parent);

But I'll try to make it clearer next time I update the documentation.

which will be URL and that parameter must be also mentioned in $breadcrumbs->push section of parent element

That's not quite right, the additional parameters can be whatever you want them to be, and you can use them however you want.

here I must put $category->sef as a second parameter of route
here $category === $category->sef

If you're saying the second one is a string, I wouldn't expect it to work - either both should be an object or both should be a string, because whatever parameters you pass to parent() are passed into the closure unaltered. (I always use Eloquent objects.)

link to Category is showing like that http://site.dev/links/{linkscat}

That's because you're not passing any parameters to route():

$breadcrumbs->push($category->title, route('links.cat'));

Should be something like this:

$breadcrumbs->push($category->title, route('links.cat', $category->sef));

And for the item:

$breadcrumbs->push($item->title, route('links.item', [$category->sef, $item->sef]));

route() itself is a standard Laravel function, documented here.

yes I saw $breadcrumbs->parent($name, $param1, ...) and $breadcrumbs->parent('category', $category->parent);
That is why I started to play and check it with different variables.

But there is no clear description what we can pass in additional parameters for $breadcrumbs->parent

Eventually I did my catalod breadcrumbs like this

// Home > Furnitura
Breadcrumbs::register('furnitura.index', function($breadcrumbs) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push('Фурнитура', route('furnitura.index'));
});
// Home > Furnitura > Cat
Breadcrumbs::register('furnitura.cat', function($breadcrumbs, $category) {
    $breadcrumbs->parent('furnitura.index');

    foreach ($category->getAncestors() as $ancestor)  {
        if( $ancestor->level > 1 )
        $breadcrumbs->push($ancestor->title, route('furnitura.cat', $ancestor->path));
        }

    $breadcrumbs->push($category->title, route('furnitura.cat', $category->path));
});
// Home > Furnitura > Cat > Item
Breadcrumbs::register('furnitura.item', function($breadcrumbs, $category, $item) {
    $breadcrumbs->parent('furnitura.cat', $category); //  $category = $category->path from links.cat
    $breadcrumbs->push($item->title, route('furnitura.item'));
});

Because if I do like described in your manual then I got home and `furnitura.index' twice in breadcrumbs. Because they are also instances of nestedset. Home level is 0, catalog index level is 1.