Laravel无需各控制器重复编码,实现全站公共Headercategory主菜单共享
全站公共头部分类数据无冗余复用实现方案
你碰到的是典型的全站公共视图数据重复传参问题,完全没必要在每个控制器里重复写查询、拆传递变量的逻辑,用Laravel原生机制就能低成本解决,零侵入修改现有控制器代码。
最适配当前场景的实现方式
核心思路是把公共分类数据的查询逻辑从控制器层抽离,放到框架启动流程里做全局共享,所有视图可以直接调用对应的变量,不用控制器挨个传。
操作步骤
- 新建专属的视图服务提供器,用来统一管理所有全局共享的视图数据,执行命令生成文件:
php artisan make:provider ViewComposerServiceProvider - 打开生成的
app/Providers/ViewComposerServiceProvider.php,在boot方法里写入分类查询逻辑,通过视图门面把数据全局共享给所有模板:<?php namespace App\Providers; use App\Models\Categories; use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; class ViewComposerServiceProvider extends ServiceProvider { public function register(): void { // } public function boot(): void { // 全局共享头部分类数据,所有模板可直接调用$Headercategory // 搭配缓存减少数据库查询压力,后台更新分类时清除对应缓存即可 View::share('Headercategory', \Cache::remember('common_header_cats', 3600, function () { return Categories::where('status', '1')->orderBy('order')->get(); })); } } - 把新建的服务提供器注册到
config/app.php的providers数组末尾,确保框架启动时能自动加载:'providers' => [ // 框架原有内置服务提供器 App\Providers\ViewComposerServiceProvider::class, ], - 把所有控制器里原来重复写的分类查询、视图传参的代码全部删掉即可。前端blade模板里原有渲染
$Headercategory的逻辑完全不用改,页面能正常拿到对应数据渲染主菜单。
可选优化(适配特殊场景)
如果你的项目不是所有页面都需要带主菜单(比如后台管理页、纯JSON接口页),不想把分类数据冗余传给所有视图,可以把全局共享改成视图精准匹配的方式:
还是在ViewComposerServiceProvider的boot方法里调整逻辑,只给引入了公共头部模板的页面注入分类数据:
public function boot(): void { // 匹配所有引入了公共头部模板的视图,自动注入分类数据 View::composer('front.layouts.header', function ($view) { $view->with('Headercategory', \Cache::remember('common_header_cats', 3600, function () { return Categories::where('status', '1')->orderBy('order')->get(); })); }); }
这种方式的好处是没有全局数据冗余,只要哪个页面引了公共头部模板,就自动拿到需要的分类数据,完全不用关心背后是哪个控制器渲染的页面。
实操避坑提醒
- 别用建基类控制器、中间件传参的方式解决这类问题,绕了一层框架流程不说,后续维护找逻辑的时候还要多翻一层上下文,不如原生视图共享机制直接。
- 原来的查询语句里
orderby记得改成规范的orderBy,避免后续Laravel大版本升级时出现兼容问题。
内容的提问来源于stack exchange,提问作者Ahmed Saad
相关产品推荐
相关产品推荐

