如何在Laravel 5中向所有视图传递数据?

145

我希望在我的Laravel 5应用程序中,所有视图都可以访问一些默认数据。

我尝试过搜索相关内容,但只找到了适用于Laravel 4的结果。我已经阅读了“共享所有视图的数据”这里的文档,但是我不知道该把以下代码放在哪里?

View::share('data', [1, 2, 3]);

谢谢你的帮助。


你需要启动代码来管理这个需求吗? - Safoor Safdar
1
在服务提供者中使用 View::share 和数据库调用的结果一起可能导致应用程序出错,当运行刷新数据库迁移或尝试运行无法连接到数据库的 dusk 时会出现此问题(长话短说,仅在运行服务提供者后才使用 .env.dusk.local)。如下所述,在基本控制器或中间件中使用是最好的选择。 - Andy Lobel
在使用视图组合器时,特别是在使用数据库查询时,使用 * 时要小心,因为它会在每个包含的子视图、组件等中运行,所以你可能会运行数百个不必要的查询。最好的方法是使用基础视图,例如 layouts.app,然后根据需要向下传递数据。 - Andy Lobel
16个回答

264

可以通过不同的方法实现这个目标,

1. 使用BaseController

我喜欢的设置方式是创建一个BaseController类来继承Laravel自带的Controller,并在其中设置各种全局配置。然后所有其他控制器都继承于BaseController而不是Laravel的Controller。

class BaseController extends Controller
{
  public function __construct()
  {
    //its just a dummy data object.
    $user = User::all();

    // Sharing is caring
    View::share('user', $user);
  }
}

2. 使用过滤器

如果你确定你需要为整个应用程序的每个请求设置视图,你也可以通过在请求之前运行的过滤器来完成这个操作。这就是我在 Laravel 中处理用户对象的方式。

App::before(function($request)
{
  // Set up global user object for views
  View::share('user', User::all());
});

或者

您可以定义自己的过滤器。

Route::filter('user-filter', function() {
    View::share('user', User::all());
});

通过简单的过滤器调用它。

根据版本5.*更新

3. 使用中间件

使用middlewareView::share

Route::group(['middleware' => 'SomeMiddleware'], function(){
  // routes
});



class SomeMiddleware {
  public function handle($request)
  {
    \View::share('user', auth()->user());
  }
}

4. 使用视图构建器

视图构建器可以帮助以不同的方式将特定数据绑定到视图中。您可以直接将变量绑定到特定视图或所有视图。例如,您可以根据要求创建自己的目录来存储视图构建器文件。这些视图构造器文件通过服务提供程序与视图进行交互。

视图构建器方法可以以不同的方式使用,第一个示例可能看起来像:

您可以创建一个App\Http\ViewComposers目录。

服务提供程序

namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
    public function boot() {
        view()->composer("ViewName","App\Http\ViewComposers\TestViewComposer");
    }
}

在此之后,在"providers"部分下将该提供者添加到config/app.php中。

TestViewComposer

namespace App\Http\ViewComposers;

use Illuminate\Contracts\View\View;

class TestViewComposer {

    public function compose(View $view) {
        $view->with('ViewComposerTestVariable', "Calling with View Composer Provider");
    }
}

ViewName.blade.php

Here you are... {{$ViewComposerTestVariable}}

这种方法只能帮助特定的视图。但是,如果您想将ViewComposer应用于所有视图,则必须将此单一更改应用于ServiceProvider。

namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
    public function boot() {
        view()->composer('*',"App\Http\ViewComposers\TestViewComposer");
    }
}

参考资料

Laravel文档

如需进一步澄清,请参考Laracast第25集

如果我的解释还不够清楚,请告诉我。


你的示例缺少 register() 方法 - 这不是可选的。 - Jonathan
不再使用5.* Laravel中的Filter作为家族的一部分,但是您当然也可以使用中间件来与视图共享数据。而中间件组则是与视图共享数据的不同角度。 - Safoor Safdar
11
这不是一个好主意。视图组合器会为每个单独的视图创建组合器实例,这意味着如果你运行了一个1000次的循环,就会创建1000个组合器实例,并且处理1000次触发事件,这并不是你想要的。 - Reza Shadman
@horse 这取决于情况,你可以从扩展类的构造函数中调用 parent::__construct(); - Safoor Safdar
4
@RezaShadman是正确的!我通过艰苦的方式学到了这一点。在安装laravel-debugbar工具进行调查之前,我的应用程序运行得非常慢。然后我意识到,对于单个页面加载,所有8个查询都将被执行约15次。这是因为每个包含的blade文件都将调用视图组合器。如果您使用星号*,那么就会出现这种情况。如果您不使用*,那么应该没有问题。 - Syclone
显示剩余7条评论

75

你可以创建自己的服务提供者(通常使用ViewServiceProvider名称),或者使用现有的AppServiceProvider

在你选择的提供者中,将你的代码放入boot方法中。

public function boot() {
    view()->share('data', [1, 2, 3]);
}

这将在所有视图中使得$data变量可访问。

如果你宁愿使用门面(facade)而非帮助函数(helper),请将view()->更改为View::,但不要忘记在文件顶部加上use View;


谢谢,运行得很好。引导功能是否适用于此类事情,还是您建议创建自己的服务提供者? - Ragnarsson
2
如果您只有一到两件事情要分享,将它放在AppServiceProvider里是可以的,但如果您有更多的内容,您应该考虑创建一个新的提供者。 - Marwelln
它之前是可以工作的,但今天我发现它不再工作了!使用 composer update 也无效。实际上,它根本没有触发 boot()。我需要共享两个变量。 - itsazzad
15
请注意,如果您正在获取数据库记录,则此方法将无法正常工作,因为此方法将在执行迁移之前调用。因此,您基本上是在尝试获取还不存在的数据库记录。至少对我来说是这样的情况。 - Karl Lorey
1
不幸的是,这似乎不能与共享已登录的用户Auth :: user()一起使用,Safoor的#1答案在此之下可以解决 :) - Stan Smulders
@lorey 如果我从Redis获取到一些缓存数据呢? - Saed Yousef

19

我发现这是最简单的方法。创建一个新的提供者,使用'*'通配符将其附加到所有视图。在5.3中也适用:-)

<?php

namespace App\Providers;

use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;

class ViewServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     * @return void
     */
    public function boot()
    {
        view()->composer('*', function ($view)
        {
            $user = request()->user();

            $view->with('user', $user);
        });
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

2
将此提供程序添加到您的config/app提供程序数组中 "App\Providers\ViewServiceProvider::class," - Nadeem0035

11

最好的方法是使用View::share('var', $value);来共享变量。

使用"*"组合视图时可能遇到的问题:

考虑以下方法:

<?php
// from AppServiceProvider::boot()
$viewFactory = $this->app->make(Factory::class);

$viewFacrory->compose('*', GlobalComposer::class);

来自一个示例的 Blade 视图:

  @for($i = 0; $i<1000; $i++)
    @include('some_partial_view_to_display_i', ['toDisplay' => $i])
  @endfor

发生了什么?

  • 使用App::make实例化GlobalComposer1000次。
  • 处理事件composing:some_partial_view_to_display_i1000次。
  • 调用GlobalComposer类中的compose函数1000次。

但是,这里的部分视图some_partial_view_to_display_i与由GlobalComposer组合的变量无关,却严重增加了渲染时间。

最佳方法?

使用View::share及其分组中间件。

Route::group(['middleware' => 'WebMiddleware'], function(){
  // Web routes
});

Route::group(['prefix' => 'api'], function (){

});

class WebMiddleware {
  public function handle($request)
  {
    \View::share('user', auth()->user());
  }
}

更新

如果你正在使用在中间件管道上计算的内容,你可以简单地监听适当的事件或将视图共享中间件放置在管道的最底部。


5
你有两个选择: 1. 在AppServiceProvider中使用Boot函数分享:

2. 创建一个全新的服务提供者类:

public function boot()
{
  view()->share('key', 'value');
}

在任何视图文件中,可以访问$key变量。

注意:请记住,您无法在此处访问当前的SessionAuthRoute数据。这个选项只适用于共享静态数据。假设您想要根据当前用户、路由或任何自定义会话变量共享一些数据,使用此选项将无法实现。

2. 使用助手类:

在您的应用程序中的任何位置创建一个助手类,并在config文件夹中的app.php文件中的别名数组中注册它。

 'aliases' => [ 
   ...,
  'Helper' => App\HelperClass\Helper::class,
 ],

并在App文件夹内的HelperClass文件夹中创建Helper.php文件:

namespace App\HelperClass;
    
class Helper
{
    public static function Sample()
    {
        //Your Code Here
    }
}

您可以随时在任何地方访问它,例如Helper::Sample()

在这里使用AuthRouteSession或任何其他类都不会受到限制。


两个都不错,但是它们在 Laravel 会话之前运行。 - BenyaminRmb

4
在文档中:
通常,您会在服务提供者的启动方法中调用share方法。您可以将它们添加到AppServiceProvider或生成一个单独的服务提供者来容纳它们。
我同意Marwelln的看法,只需将其放入boot函数的AppServiceProvider中即可:
public function boot() {
    View::share('youVarName', [1, 2, 3]);
}

我建议为变量使用特定名称,以避免与其他非“全局”变量混淆或出错。


3

文档可以在这里找到 https://laravel.com/docs/5.4/views#view-composers,但我会对其进行简要解释。

  1. Look for the directory app\Providers in the root directory of your application and create the file ComposerServiceProvider.php and copy and past the text below into it and save it.

    <?php
        namespace App\Providers;
        use Illuminate\Support\Facades\View;
        use Illuminate\Support\ServiceProvider;
    
        class ComposerServiceProvider extends ServiceProvider
        {
            /**
            * Register bindings in the container.
            *
            * @return void
            */
        public function boot()
        {
            // Using class based composers...
            View::composer(
                'profile', 'App\Http\ViewComposers\ProfileComposer'
            );
    
            // Using Closure based composers...
            View::composer('dashboard', function ($view) {
                //
            });
        }
    
        /**
        * Register the service provider.
        *
        * @return void
        */
        public function register()
        {
            //
        }
    }
    
  2. From the root of your application open Config/app.php and look for the Providers section in the file and copy and past this 'App\Providers\ComposerServiceProvider', to the array.

通过这样做,我们创建了Composer服务提供者。当您使用视图“Profile”运行应用程序时,例如:http://yourdomain/something/profile,服务提供者ComposerServiceProvider被调用,并实例化类App\Http\ViewComposers\ProfileComposer,由于在boot方法或函数中的以下代码调用Composer方法。
 // Using class based composers...
 View::composer(
   'profile', 'App\Http\ViewComposers\ProfileComposer'
 );
  1. 如果您刷新应用程序,将会出现错误,因为类App\Http\ViewComposers\ProfileComposer尚不存在。现在让我们创建它。

前往目录路径app/Http

  • Create the directory called ViewComposers

  • Create the file ProfileComposer.php.

    class ProfileComposer
    {
        /**
        * The user repository implementation.
        *
        * @var UserRepository
        */
        protected $users;
    
        /**
        * Create a new profile composer.
        *
        * @param  UserRepository  $users
        * @return void
        */
        public function __construct(UserRepository $users)
        {
            // Dependencies automatically resolved by service container...
            $this->users = $users;
        }
    
        /**
        * Bind data to the view.
        *
        * @param  View  $view
        * @return void
        */
        public function compose(View $view)
        {
            $view->with('count', $this->users->count());
        }
    }
    

现在进入您的视图,或者在这种情况下是Profile.blade.php文件,并添加以下内容:

{{ $count }}

您需要在个人资料页面显示用户数量。为了在所有页面上显示数量,请更改

// Using class based composers...
View::composer(
    'profile', 'App\Http\ViewComposers\ProfileComposer'
);

To

// Using class based composers...
View::composer(
    '*', 'App\Http\ViewComposers\ProfileComposer'
);

ProfileComposer.php缺少<?php和namespace App\Http\ViewComposers; use Illuminate\Contracts\View\View;。 - Unicco

2

1) In (app\Providers\AppServiceProvider.php)

// in boot function
       view()->composer('*', function ($view) {
            $data = User::messages();
            $view->with('var_messages',$data);
        });

2) 在您的用户模型中

  public static function messages(){ // this is just example
        $my_id = auth()->user()->id;
        $data= Message::whereTo($my_id)->whereIs_read('0')->get(); 
        return $data; // return is required
    }

3) 在您的视角中

(涉及IT技术)
 {{ $var_messages }}

1

在你的config文件夹中,你可以创建一个名为"variable.php"的php文件,其内容如下:

<?php

  return [
    'versionNumber' => '122231',
  ];

现在,在所有视图中,您可以像这样使用它:
config('variable.versionNumber')

在某些情况下,我会这样做,因为信息真正是全局的,您可以从任何地方访问它。出于这个原因,我将配置文件称为“global.php”,并将任何我想要在代码的所有其他部分中访问的内容放在其中。唯一的限制是这仅适用于静态数据,并且被缓存。如果您有不断变化的数据,则不应以这种方式使用它。 - eResourcesInc

1

Laravel 5.6 方法:https://laravel.com/docs/5.6/views#passing-data-to-views

例如,将模型集合共享到所有视图中(AppServiceProvider.php):

use Illuminate\Support\Facades\View;
use App\Product;

public function boot()
{
    $products = Product::all();
    View::share('products', $products);

}

2
如果您尝试使用空数据库创建新应用程序,这将会导致问题。 - Chris Herbert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接