diglactic / laravel-breadcrumbs

Laravel Breadcrumbs - A simple Laravel-style way to create breadcrumbs.
https://packagist.org/packages/diglactic/laravel-breadcrumbs
MIT License
868 stars 63 forks source link

Same name routes with parameters #39

Closed DriverCat closed 2 years ago

DriverCat commented 2 years ago

I have these routes in my web.php:

Route::prefix('{model}/{model_id}')->group(function() { Route::resource('audits', AuditController::class)->only([ 'index', 'show' ]); });

So, for different models I have a route, such as: /customer/1/audits (/user/4/audits) and /customer/1/audits/1 (/user/4/audits/2)

How do I define breadcrumbs for these routes, as they have same name and the package requires a route name for breadcrumb?

shengslogar commented 2 years ago

What's stopping you from giving this a route name? You won't be able to take advantage of route-model binding here, but you can still place your routing logic inside the breadcrumb definition.

Breadcrumbs::for('audits.index', function (BreadcrumbTrail $trail, $model, $modelId) {
    // ...
});
DriverCat commented 2 years ago

My bad, I was using it in a loop ) Thank you! By the way, as I have much similar routes in order not to copy them in breadcrumbs.php, I implemented it in this way:

I extend Breadcrumbs facade with MyBreadcrumbs and I call my new facade from breadcrumbs.php:

use App\Facades\MyBreadcrumbs;

MyBreadcrumbs::getResourceBreadcrumbs();

Inside MyBreadcrumbs, I get all my routes, excluding some that I dont need:

public static function getResourceBreadcrumbs(): bool
    {
        $allWebRoutes = self::getWebRoutes();

        foreach($allWebRoutes as $routeName => $routeActions) {
            self::getModelBreadcrumbs($routeActions, $routeName);
        }

        self::getAuditBreadcrumbs();

        return true;
    }

private static function getWebRoutes(): array
    {
        $routeNames = [];
        $routeCollection = Route::getRoutes();

        foreach ($routeCollection as $route) {
            $routeMiddleware = $route->getAction()['middleware'] ?? [];
            $routeName = $route->getName();

            if(!in_array('web', $routeMiddleware) or empty($routeName))
                continue;

            $routeNameParts = explode('.', $routeName);
            if(!isset($routeNameParts[1]))
                continue;

            $routeNames[$routeNameParts[0]][] = $routeNameParts[1];
        }

        unset(
            $routeNames['password'],
            $routeNames['audits'],
            $routeNames['verification'],
        );

        return $routeNames;
    }

For each route action (excluding some), I add breadcrumbs:

private static function getModelBreadcrumbs(array $routeActions, string $routeName): void
    {
        $routeActions = array_diff($routeActions,[
            'store',
            'destroy',
            'update',
        ]);

        foreach($routeActions as $routeAction) {
            self::{'get' . Str::ucfirst($routeAction) . 'Breadcrumbs'}($routeName);
        }
    }

For, example, this is for show method:

private static function getShowBreadCrumbs($routeName): void
    {
        // [Models] > [Model]
        MyBreadcrumbs::for($routeName . '.show', function ($trail, $model) use ($routeName) {
            $trail->parent($routeName . '.index');
            $trail->push($model->name, route($routeName . '.show', [Str::singular($routeName) => $model->id, 'locale' => App::getLocale()]));
        });
    }

And in my case of auditing models, I add audit.index and audit.show actions breadcrumbs:

private static function getAuditBreadcrumbs(): void
    {
        // [Models] > [Model] > [Audits]
        MyBreadcrumbs::for('audits.index', function ($trail, $model) {
            $trail->parent($model->getTable() . '.show', $model);
            $trail->push(trans('app.buttons.audit'), route('audits.index', ['locale' => App::getLocale(),'model' => $model->getTable(),'model_id' => $model->id]));
        });
        // [Models] > [Model] > [Audits] > [Audit]
        MyBreadcrumbs::for('audits.show', function ($trail, $model, $audit) {
            $trail->parent('audits.index', $model);
            $trail->push($audit->created_at, route('audits.show', ['locale' => App::getLocale(),'model' =>$model->getTable(),'model_id' => $model->id,'audit' => $audit->id]));
        });
    }

Hope, it helps someone.

shengslogar commented 2 years ago

Nice! Glad you figured it out 🥂