使用Laravel View Composers在视图之间共享数据

Laravel视图入门 ( Getting Started With Laravel Views )

Views hold the presentation logic of a Laravel application. It is served separately from the application logic using laravel's blade templating engine.

视图具有Laravel应用程序的表示逻辑。 它使用laravel的刀片模板引擎与应用程序逻辑分开提供。

Passing data from a controller to a view is as simple as declaring a variable and adding it as a parameter to the returned view helper method. There is no shortage of ways to do this.

将数据从控制器传递到视图就像声明变量并将其作为参数添加到返回的视图帮助器方法一样简单。 不乏方法。

We will create a SampleController class that will handle our logic

我们将创建一个SampleController类来处理我们的逻辑

php artisan make:controller SampleController

Here is a sample controller in app/Http/Controllers/SampleController.php

这是app/Http/Controllers/SampleController.php的示例控制器

class SampleController extends Controller
{
    /**
     * pass an array to the 'foo' view
     * as a second parameter.
    */
    public function foo()
    {
        return view('foo', [
            'key' => 'The big brown fox jumped over the lazy dog'
        ]);
    }

    /**
     * Pass a key variable to the 'foo view
     * using the compact method as
     * the second parameter.
    */
    public function bar()
    {
        $key = 'If a would chuck can chuck wood,';

        return view('foo', compact('key'));
    }

    /**
     * Pass a key, value pair to the view
     * using the with method.
    */
    public function baz()
    {
        return view('foo')->with(
            'key',
            'How much woood would a woodchuck chuck.'
        );
    }
}

将数据传递到多个视图 ( Passing Data To Multiple Views )

This is all fine and dandy. Well it is until you try passing data to many views.

这一切都很好,花花公子。 好吧,直到您尝试将数据传递到许多视图为止。

More often than not, we need to get some data on different pages. One such scenario would be information on the navigation bar or footer that we be available across all pages on your website, say, the most recent movie in theatres.

通常,我们需要在不同页面上获取一些数据。 一种这样的情况是导航栏或页脚上的信息,我们可以在您网站的所有页面上找到这些信息,例如剧院中的最新电影。

For this example, we will use an array of 5 movies to display the latest movie (the last item on the array) on the navigation bar.

对于此示例,我们将使用5个电影的数组在导航栏上显示最新的电影(数组中的最后一项)。

For this, I will use a boostrap template to setup the navigation bar in resources/views/app.blade.php.

为此,我将使用boostrap模板在resources/views/app.blade.php设置导航栏。

<nav class="navbar navbar-inverse">
        <div class="container-fluid">

            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="/">Movie Maniac</a>
            </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    <li><a href="foo">Foo</a></li>
                    <li><a href="bar">Bar</a></li>
                    <li><a href="baz">Baz</a></li>
                </ul>

                <ul class="nav navbar-nav navbar-right">
                    <li><a href="#">latest movie title here</a></li>
                </ul>

            </div>
            <!-- /.navbar-collapse -->
        </div>
        <!-- /.container-fluid -->
    </nav>

Placeholder text for latest movie on navbar

The latest movie text on the far right will however be replaced with a title from our movie list to be created later on.

但是,最右边的最新电影文本将替换为电影列表中的标题,以便稍后创建。

Let's go ahead and create our movie list on the homepage.

让我们继续在主页上创建电影列表。

路线 (Routes)

View all the routes in app/Http/routes.php

查看app/Http/routes.php所有路由

Route::get('/', 'SampleController@index');

Route::get('/foo', 'SampleController@foo');

Route::get('/bar', 'SampleController@bar');

Route::get('/baz', 'SampleController@baz');

We are just creating four simple routes.

我们只是在创建四个简单的路线。

控制者 (Controller)

View the controller in app/Http/Controllers/SampleController.php

app/Http/Controllers/SampleController.php查看控制器

/**
     * Return a list of the latest movies to the
     * homepage
     *
     * @return View
     */
    public function index()
    {
        $movieList = [
            'Shawshank redemption',
            'Forrest Gump',
            'The Matrix',
            'Pirates of the Carribean',
            'Back to the future',
        ];

        return view('welcome', compact('movieList'));
    }

视图 (View)

See latest movie views in resources/views/welcome.blade.php

resources/views/welcome.blade.php查看最新的电影观看

@extends('app')

@section('content')<h1>Latest Movies</h1>
        <ul>
        @foreach($movieList as $movie)
            <li class="list-group-item"><h5>{{ $movie }}</h5></li>
        @endforeach
        </ul>
@endsection

It goes without saying that my idea of latest movies is skewed, but we can overlook that for now. Here is what our homepage looks like now.

毋庸置疑,我对最新电影的想法是歪曲的,但现在我们可以忽略它。 这是我们主页现在的样子。

Homepage with list of latest movies

Awesome! We have our movie list. And now to the business of the day.

太棒了! 我们有电影清单。 如今已成为当今的业务。

更新索引控制器方法 ( Update Index Controller Method )

We will assume that Back to the future, being the last movie on our movie list, is the latest movie, and display it as such on the navigation bar.

我们将假设Back to the future (电影列表中的最后一部电影)是最新的电影,并在导航栏上将其显示为最新电影。

/**
     * Return a list of the latest movies to the
     * homepage
     *
     * @return View
     */
    public function index()
    {
        $movieList = [
            'Shawshank redemption',
            'Forrest Gump',
            'The Matrix',
            'Pirates of the Carribean',
            'Back to the future',
        ];

        $latestMovie = end($movieList);

        return view('welcome', compact('movieList', 'latestMovie'));
    }

共享视图文件中的错误 ( Error In Shared View File )

We now have Back to the future as our latest movie, and rightfully so because Back to the Future 4 was released a week from now in 1985. I cannot make this stuff up.

现在,我们拥有《 回到未来》作为我们的最新电影,这是正确的,因为《 回到未来》 4是从1985年开始的一周后发行的。我无法弥补这一点。

Homepage with latest movie on nav bar

This seems to work. Well until you try navigating to other pages (Try one of foo, bar, baz) created earlier on. This will throw an error.

这似乎有效。 好吧,直到您尝试导航到之前创建的其他页面(尝试foo,bar,baz之一)。 这将引发错误。

Error due to missing latest movie on nav bar

修复共享视图中的错误 ( Fixing Error in Shared View )

This was expected and by now you must have figured out why this happened. We declared the latest movie variable on the index method of the controller and passed it to the welcome biew. By extension, we made latestMovie available to the navigation bar BUT only to views/welcome.blade.php.

这是预料之中的,现在您必须已经弄清楚了为什么会发生这种情况。 我们在控制器的index方法上声明了最新的movie变量,并将其传递给了welcome biew。 通过扩展,我们使latestMovie仅可用于views/welcome.blade.php 可用于导航栏。

When we navigate to /foo, our navigation bar still expects a latestMovie variable to be passed to it from the foo method but we have none to give.

当我们导航到/foo ,导航栏仍然期望从foo方法传递一个latestMovie变量给我们,但是我们没有任何变量。

There are three ways to fix this

有三种方法可以解决此问题

  • Declare the latestMovie value in every other method, and in this case, the movieList too. It goes without saying we will not be doing this.

    在其他所有方法中声明latestMovie值,在这种情况下, movieList 。 不用说我们不会这样做。

  • Place the movie information in a service provider's boot method. You can place it on App/Providers/AppServiceProvider or create one. This quickly becomes inefficient if we are sharing alot of data.

    将影片信息放入服务提供商的启动方法中 。 您可以将其放在App/Providers/AppServiceProvider或创建一个。 如果我们共享大量数据,这很快就会变得效率低下。

/**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        view()->share('key', 'value');
    }
  • Take advantage of Laravel View composers

    利用Laravel View作曲家

输入左:Laravel View作曲家 ( Enter Left: Laravel View Composers )

View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location.

视图编写器是呈现视图时调用的回调或类方法。 如果您有想要在每次渲染视图时将其绑定到视图的数据,则视图编辑器可以帮助您将该逻辑组织到一个位置。

-Laravel documentation

-Laravel文档

While it is possible to get the data in every controller method and pass it to the single view, this approach may be undesirable.

尽管可以通过每种控制器方法获取数据并将其传递给单个视图,但是这种方法可能是不可取的。

View composers, as described from the laravel documentation, bind data to a view every time it is rendered. They clean our code by getting fetching data once and passing it to the view.

如laravel文档中所述,视图编写器在每次呈现时都将数据绑定到视图。 他们通过一次获取数据并将其传递给视图来清理代码。

创建一个新的服务提供商 ( Creating A New Service Provider )

Since Laravel does not include a ViewComposers directory in it's application structure, we will have to create our own for better organization. Go ahead and create App\Http\ViewComposers

由于Laravel在其应用程序结构中未包含ViewComposers目录,因此我们将必须创建自己的目录以更好地进行组织。 继续创建App\Http\ViewComposers

We will then proceed to create a new service provider to handle all our view composers using the artisan command

然后,我们将继续创建新的服务提供者,以使用artisan command处理所有视图撰写者

php artisan make:provider ComposerServiceProvider

The service provider will be visible in app/Providers

服务提供商将显示在app/Providers

Add the ComposerServiceProvider class to config/app.php array for providers so that laravel is able to identify it.

ComposerServiceProvider类添加到providers config/app.php数组中,以便laravel能够识别它。

Modify the boot method in the new Provider by adding a composer method that extends view()

通过添加扩展view()composer方法,在新Provider中修改boot方法。

/**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        view()->composer(
            'app',
            'App\Http\ViewComposers\MovieComposer'
        );
    }

Laravel will execute a MovieComposer@compose method every time app.blade.php is rendered. This means that every time our navigation bar is loaded, we will be ready to serve it with the latest movie from our view composer.

Laravel将执行一个MovieComposer@compose方法每次 app.blade.php呈现。 这意味着每次加载导航栏时,我们都准备将其与视图编辑器中的最新电影一起提供。

While MovieComposer@compose is the default method to be called, you can overwrite it by specifying your own custom method name in the boot method.

虽然MovieComposer@compose是要调用的默认方法,但是您可以通过在启动方法中指定自己的自定义方法名称来覆盖它。

view()->composer('app',  'App\Http\ViewComposers\MovieComposer@foobar');

创建MovieComposer ( Creating MovieComposer )

Next, we will create our MovieComposer class

接下来,我们将创建MovieComposer

<?php

namespace App\Http\ViewComposers;

use Illuminate\View\View;

class MovieComposer
{
    public $movieList = [];
    /**
     * Create a movie composer.
     *
     * @return void
     */
    public function __construct()
    {
        $this->movieList = [
            'Shawshank redemption',
            'Forrest Gump',
            'The Matrix',
            'Pirates of the Carribean',
            'Back to the future',
        ];
    }

    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)
    {
        $view->with('latestMovie', end($this->movieList));
    }
}

The with method will bind the latestMovies to the app view when it is rendered. Notice the we added Illuminate\View\View .

呈现时, with方法会将latestMovies绑定到app视图。 注意,我们添加了Illuminate\View\View

使用MovieComposer清理控制器 ( Cleaning Up The Controller with MovieComposer )

We can now get rid of the latestMovie variable and actually remove it from the compact helper method in SampleController@index.

现在,我们可以摆脱latestMovie变量,并实际上从SampleController@indexcompact帮助器方法中将其删除。

public function index()
    {
        $movieList = [
            'Shawshank redemption',
            'Forrest Gump',
            'The Matrix',
            'Pirates of the Carribean',
            'Back to the future',
        ];

        return view('welcome', compact('movieList'));
    }

We can now access the latest movie on the navigation bar in all our routes.

现在,我们可以在所有路线的导航栏中访问最新的电影。

View latest movies in all routes

使用存储库优化代码 ( Optimizing Our Code With A Repository )

While we seem to have solved one issue, we seem to have created another. we now have two movieList arrays. one in the controller and one in the constructor method in MovieComposer.

虽然我们似乎已经解决了一个问题,但我们似乎创造了另一个问题。 我们现在有两个movieList数组。 在MovieComposer ,一个在控制器中,一个在构造函数中。

While this may have been caused by using an array as a simple data source, it may be a good idea to fix it, say, by creating a movie repository. Ideally, the latestMovie value would be gotten from a database using Eloquent.

尽管这可能是由于使用数组作为简单的数据源而引起的,但最好通过创建电影资料库来修复它,这是一个好主意。 理想情况下, latestMovie值将使用数据库中得到雄辩

Check out the github repo for this tutorial to see how I created a Movie Repository to get around the redudancy as shown below in MovieComposer and SampleController.

查阅本教程的github存储库,以了解如何创建Movie Repository来避免重复,如下MovieComposerSampleController

public $movieList = [];

    /**
     * Create a movie composer.
     *
     *  @param MovieRepository $movie
     *
     * @return void
     */
    public function __construct(MovieRepository $movies)
    {
        $this->movieList = $movies->getMovieList();
    }

    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)
    {
        $view->with('latestMovie', end($this->movieList));
    }
public function index(MovieRepository $movies)
    {
        $movieList = $movies->getMovieList();

        return view('welcome', compact('movieList'));
    }

结论 ( Conclusion )

It is possible to create a view composer that is executed when all views are rendered by replacing the view name with an asterisk wildcard

通过用星号通配符替换视图名称,可以创建在渲染所有视图时执行的视图编辑器

view()->composer('*', function (View $view) {
    //logic goes here
});

Notice that instead of passing a string with the path to MovieComposer, you can also pass a closure.

注意,除了传递带有MovieComposer路径的字符串之外,还可以传递闭包。

You can as also limit the view composer to a finite number of views, say, nav and footer

您还可以将视图编辑器限制为有限数量的视图,例如navfooter

view()->composer(
    ['nav', 'footer'],
    'App\Http\ViewComposers\MovieComposer'
);

翻译自: https://scotch.io/tutorials/sharing-data-between-views-using-laravel-view-composers

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值