在Laravel中,如何在每次编译前在运行时更改视图内容


in Laravel how to change the view content at runtime each time before compilation

在Laravel 5中,我需要在编译前修改视图内容,添加这个字符串:"@extends(foo)"

注释:更改视图文件内容不是一个选项

所以这个过程类似于(每次调用一个视图)

  1. 获取视图内容
  2. 通过附加"@extends(foo)"关键字编辑视图内容
  3. 编译(渲染)视图

我已经尝试使用viewcomposer和中间件没有运气

这是我的作曲服务提供商:

namespace App'Providers;
use Illuminate'Support'Facades'View;
use Illuminate'Support'ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
    public function boot()
    {
        View::composer('pages/*', function ($view) {
             // i want to do the following:
             // 1- find all view under directory resources/views/pages
             // 2- then add the following blade command "@extends(foo)" at the beginning of the view before compile
        });
    }

    public function register()
    {
        //
    }
}

这是我的视图中间件尝试(在中间件中,我能够在编译后修改视图内容:()

<?php
namespace App'Http'Middleware;
use Closure;
class ViewMiddleware
{
    public function handle($request, Closure $next)
    {
        $response =  $next($request);
        if (!method_exists($response,'content')) {
            return $response;
        }
        $content  = "@extends('layouts.app')".$response->content();
        $response->setContent($content);
        return $response;
    }
}

感谢

:我需要完成的是扩展视图的布局基于他们的父目录

例如,我的视图目录有以下结构

我需要视图"controlpanel.blade.php"有布局"layout/admin.blade.php"因为它的父文件夹被称为"admin"

-view
  |--pages
    |--admin
      |--controlpanel.blade.php
  |--layouts
     |--admin.blade.php 

这不是一件容易的事。你需要替换Laravel的刀片编译器类。它应该从当前视图路径中获取主布局,而不是从@extends指令中获取。

配置/app.php:删除原来的服务提供者

Illuminate'View'ViewServiceProvider::class

加上你的
App'Providers'BetterViewServiceProvider::class

在你的服务提供商app/BetterViewServiceProvider.php唯一重要的事情是调用' app 'BetterBladeCompiler而不是原来的Illuminate'View'Compilers'BladeCompiler,其余方法是从parent复制的。

<?php namespace App'Providers;

use Illuminate'View'Engines'CompilerEngine;
use Illuminate'View'ViewServiceProvider;
class BetterViewServiceProvider extends ViewServiceProvider
{
    /**
     * Register the Blade engine implementation.
     *
     * @param  'Illuminate'View'Engines'EngineResolver  $resolver
     * @return void
     */
    public function registerBladeEngine($resolver)
    {
        $app = $this->app;
        // The Compiler engine requires an instance of the CompilerInterface, which in
        // this case will be the Blade compiler, so we'll first create the compiler
        // instance to pass into the engine so it can compile the views properly.
        $app->singleton('blade.compiler', function ($app) {
            $cache = $app['config']['view.compiled'];
            return new 'App'BetterBladeCompiler($app['files'], $cache);
        });
        $resolver->register('blade', function () use ($app) {
            return new CompilerEngine($app['blade.compiler']);
        });
    }
}

现在在app'BetterBladeCompiler.php重写compileExtends方法并改变它的行为,以这种方式读取当前路径并插入视图文件之前的最后一个目录到表达式,将被其他Laravel文件解释。

<?php namespace App;
use Illuminate'View'Compilers'BladeCompiler;
use Illuminate'View'Compilers'CompilerInterface;
class BetterBladeCompiler extends BladeCompiler implements CompilerInterface
{
    /**
     * Compile the extends statements into valid PHP.
     *
     * @param  string  $expression
     * @return string
     */
    protected function compileExtends($expression)
    {
        // when you want to apply this behaviour only to views from specified directory "views/pages/"
        // just call a parent method
        if(!strstr($this->path, '/pages/')) {
            return parent::compileExtends($expression);
        }
        // explode path to view
        $parts = explode('/', $this->path);
        // take directory and place to expression
        $expression = '''layouts.' . $parts[sizeof($parts)-2] . '''';
        $data = "<?php echo '$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
        $this->footer[] = $data;
        return '';
    }
}

代码来自Laravel 5.2。经过测试,但不是太多。

如果你想'动态'扩展视图,这里有一个方法:

$view = 'foo';  // view to be extended
$template = view('home')->nest('variable_name', $view, ['data' => $data]);
return $template->render();

在你看来:

@if (isset($variable_name))
    {!! $variable_name !!}
@endif

这在Laravel 5.2中为我工作。

我仍然认为组织视图并让它们扩展相应的布局比动态传递更容易。

编辑:

这里有另一种方法。但是没有检入最新版本的Laravel。

在你看来:

@extends($view)

and in controller:

$view = 'foo';
return view('someview', compact('view'));

我建议使用laravel叶片堆叠。裁判:https://laravel.com/docs/5.3/blade栈

Blade允许你推送到命名的堆栈,这些堆栈可以在另一个视图或布局的其他地方呈现。

所以不用扩展'foo',只需要使用栈来推送'foo'视图。

这里有一些链接和讨论供您参考:

在Blade中Section和Stack有什么区别?

https://laracasts.com/discuss/channels/general-discussion/blade-push-and-stack-are-they-here-to-stay

http://laraveltnt.com/blade-stack-push/

https://laracasts.com/discuss/channels/laravel/blade-stacks-pushing-into-an-included-view