d13r / laravel-breadcrumbs

Please see the Diglactic fork.
https://github.com/diglactic/laravel-breadcrumbs
2.34k stars 416 forks source link

Breadcrumb on resource returning non-object error #38

Closed joedawson closed 10 years ago

joedawson commented 10 years ago

Hey, loving this package thus' far.

I've read through all docs, but unfortunately can't work out my issue.

ErrorException Trying to get property of non-object (View: /Users/joedawson/Development/tekkers/app/views/layouts/single.blade.php) (View: /Users/joedawson/Development/tekkers/app/views/layouts/single.blade.php)

app/routes.php

Route::get('/', ['uses' => 'PagesController@home', 'as' => 'home']);
Route::resource('videos', 'VideosController');

app/controllers/VideosController.php

class VideosController extends \BaseController {

    public function index()
    {
        $videos = Video::all();
        return View::make('videos.index', compact('videos'));
    }

    public function show($slug)
    {
        $video = Video::where('slug', '=', $slug)->first();

        if(is_null($video)) {
            return Redirect::to('videos');
        }

        return View::make('videos.show', compact('video'));
    }

}

app/views/videos/show.blade.php

@extends('layouts.single')

@section('title', $video->title)

@section('content')
    {{ $video->description }}
@stop

app/views/layouts/single.blade.php

<!DOCTYPE html>
<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7"><![endif]-->
<!--[if IE 7]><html class="no-js lt-ie9 lt-ie8"><![endif]-->
<!--[if IE 8]><html class="no-js lt-ie9"><![endif]-->
<!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]-->
<head>
    @include('layouts.inc.meta')
</head>
<body>
    @include('layouts.inc.header')
    <div class="container">
        <div class="content">
            <h1>@yield('title')</h1>
            {{ Breadcrumbs::renderIfExists() }}
            @yield('content')
        </div>
        @include('layouts.inc.footer')
    </div>
</body>
</html>

app/breadcrumbs.php - I actually read through #18 for my breadcrumbs boilerplate.

Breadcrumbs::register('home', function($breadcrumbs) {
    $breadcrumbs->push('Home', route('home'));
});

Breadcrumbs::register('videos.index', function($breadcrumbs) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push('Videos', route('videos.index'));
});

Breadcrumbs::register('videos.show', function($breadcrumbs, $video) {
    $breadcrumbs->parent('videos.index');
    $breadcrumbs->push($video->title, route('videos.index', $video->slug));
});

When I replace;

Breadcrumbs::register('videos.show', function($breadcrumbs, $video) {
    $breadcrumbs->parent('videos.index');
    $breadcrumbs->push($video->title, route('videos.index', $video->slug));
});

With:

Breadcrumbs::register('videos.show', function($breadcrumbs, $video) {
    $breadcrumbs->parent('videos.index');
    $breadcrumbs->push($video, route('videos.index', $video));
});

$video returns the 'slug'. Not throwing any errors, but rendering breadcrumbs like so:

Home / Videos / my-slug-string

Providers

'providers' => array(
    'Illuminate\Foundation\Providers\ArtisanServiceProvider',
    'Illuminate\Auth\AuthServiceProvider',
    'Illuminate\Cache\CacheServiceProvider',
    'Illuminate\Session\CommandsServiceProvider',
    'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider',
    'Illuminate\Routing\ControllerServiceProvider',
    'Illuminate\Cookie\CookieServiceProvider',
    'Illuminate\Database\DatabaseServiceProvider',
    'Illuminate\Encryption\EncryptionServiceProvider',
    'Illuminate\Filesystem\FilesystemServiceProvider',
    'Illuminate\Hashing\HashServiceProvider',
    'Illuminate\Html\HtmlServiceProvider',
    'Illuminate\Log\LogServiceProvider',
    'Illuminate\Mail\MailServiceProvider',
    'Illuminate\Database\MigrationServiceProvider',
    'Illuminate\Pagination\PaginationServiceProvider',
    'Illuminate\Queue\QueueServiceProvider',
    'Illuminate\Redis\RedisServiceProvider',
    'Illuminate\Remote\RemoteServiceProvider',
    'Illuminate\Auth\Reminders\ReminderServiceProvider',
    'Illuminate\Database\SeedServiceProvider',
    'Illuminate\Session\SessionServiceProvider',
    'Illuminate\Translation\TranslationServiceProvider',
    'Illuminate\Validation\ValidationServiceProvider',
    'Illuminate\View\ViewServiceProvider',
    'Illuminate\Workbench\WorkbenchServiceProvider',
    'Way\Generators\GeneratorsServiceProvider',
    'DaveJamesMiller\Breadcrumbs\ServiceProvider'
)

Aliases

'aliases' => array(
    'App'             => 'Illuminate\Support\Facades\App',
    'Artisan'         => 'Illuminate\Support\Facades\Artisan',
    'Auth'            => 'Illuminate\Support\Facades\Auth',
    'Blade'           => 'Illuminate\Support\Facades\Blade',
    'Cache'           => 'Illuminate\Support\Facades\Cache',
    'ClassLoader'     => 'Illuminate\Support\ClassLoader',
    'Config'          => 'Illuminate\Support\Facades\Config',
    'Controller'      => 'Illuminate\Routing\Controller',
    'Cookie'          => 'Illuminate\Support\Facades\Cookie',
    'Crypt'           => 'Illuminate\Support\Facades\Crypt',
    'DB'              => 'Illuminate\Support\Facades\DB',
    'Eloquent'        => 'Illuminate\Database\Eloquent\Model',
    'Event'           => 'Illuminate\Support\Facades\Event',
    'File'            => 'Illuminate\Support\Facades\File',
    'Form'            => 'Illuminate\Support\Facades\Form',
    'Hash'            => 'Illuminate\Support\Facades\Hash',
    'HTML'            => 'Illuminate\Support\Facades\HTML',
    'Input'           => 'Illuminate\Support\Facades\Input',
    'Lang'            => 'Illuminate\Support\Facades\Lang',
    'Log'             => 'Illuminate\Support\Facades\Log',
    'Mail'            => 'Illuminate\Support\Facades\Mail',
    'Paginator'       => 'Illuminate\Support\Facades\Paginator',
    'Password'        => 'Illuminate\Support\Facades\Password',
    'Queue'           => 'Illuminate\Support\Facades\Queue',
    'Redirect'        => 'Illuminate\Support\Facades\Redirect',
    'Redis'           => 'Illuminate\Support\Facades\Redis',
    'Request'         => 'Illuminate\Support\Facades\Request',
    'Response'        => 'Illuminate\Support\Facades\Response',
    'Route'           => 'Illuminate\Support\Facades\Route',
    'Schema'          => 'Illuminate\Support\Facades\Schema',
    'Seeder'          => 'Illuminate\Database\Seeder',
    'Session'         => 'Illuminate\Support\Facades\Session',
    'SoftDeletingTrait' => 'Illuminate\Database\Eloquent\SoftDeletingTrait',
    'SSH'             => 'Illuminate\Support\Facades\SSH',
    'Str'             => 'Illuminate\Support\Str',
    'URL'             => 'Illuminate\Support\Facades\URL',
    'Validator'       => 'Illuminate\Support\Facades\Validator',
    'View'            => 'Illuminate\Support\Facades\View',
    'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade'
)

Breadcrumbs Version: dev-master Laravel Version: 4.2.6 PHP Version: 5.5.12

I hope I've provided you with everything you need :+1:

d13r commented 10 years ago

Thanks for the level of detail.

$video contains the URL slug, not an object, because it takes the same parameters as the controller - specifically this line:

public function show($slug)

There are a few possible solutions to this:

  1. Use route model binding to move the conversion from slug to object into app/routes.php (recommended - this is what the docs assume). Since you're using slugs not IDs, you'll have to use Route::bind() in place of Route::model():

    Route::bind('videos', function($slug) {
       $video = Video::where('slug', '=', $slug)->first();
       if (!$video) throw new ModelNotFoundException;
       return $video;
    });

    This way both the controller and breadcrumbs will receive a model object, $video, instead of $slug. (Note: I've never tried that with Route::resource(), but the docs imply it will still work.)

  2. Re-load the model in app/breadcrumbs.php:

    Breadcrumbs::register('videos.show', function($breadcrumbs, $slug) {
       $video = Video::where('slug', '=', $slug)->first();
       $breadcrumbs->parent('videos.index');
       $breadcrumbs->push($video->title, route('videos.show', $video->slug));
    });

    (But that adds a redundant database call.)

  3. Pass it from the view manually:

    @section('breadcrumbs', Breadcrumbs::render('videos.show', $video))

Hope that helps.

joedawson commented 10 years ago

Thanks for the explanation Dave, I went for the third solution. Appreciate your time :)

filipzelic commented 10 years ago

Hey Dave, I have similar issue. Is there a way to pass objects directly from controller to breadcrumbs. I don't want to pass model directly from routes, and also I can't pass it from view, because I have set bc::render in my default layout. Having if statement for every page is not an option..

Thanks very much

d13r commented 10 years ago

You might be able to access the view variables directly from the controller... I've not tried that though, depends how Laravel is set up.

Or you can use Breadcrumbs::setCurrentRoute($name, $param1, $param2...) in the controller.