В Laravel, как изменять содержимое представления во время выполнения каждый раз перед компиляцией

в Laravel 5 Мне нужно изменить содержимое представления во время выполнения перед компиляцией, добавив эту строку: "@extends (foo)"

note: изменение содержимого файла не является параметром

поэтому процесс будет чем-то вроде (каждый раз, когда вызывается представление)

  • получение содержимого представления
  • отредактируйте содержимое представления, добавив ключевое слово @extends (foo)
  • скомпилировать (визуализировать) представление

Я пробовал использовать 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;
    }
}

Спасибо

Обновление: что мне нужно выполнить, - это расширение представлений с помощью макетов на основе их родительских каталогов.

например, каталог my view имеет следующую структуру

Мне нужно представление "controlpanel.blade.php", чтобы иметь макет "layout/admin.blade.php", потому что его родительская папка называется "admin"

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

Ответ 1

Нелегкая задача. Вам нужно заменить класс компилятора blade-сервера Laravel. Он должен взять основной макет из текущего пути просмотра, а не из директивы @extends.

конфигурации/app.php: удалить оригинального поставщика услуг

Illuminate\View\ViewServiceProvider::class

добавить свои

App\Providers\BetterViewServiceProvider::class

В вашем сервис-провайдере app/BetterViewServiceProvider.php важно только вызвать \App\BetterBladeCompiler вместо оригинального Illuminate\View\Compilers\BladeCompiler, остальное метод копируется из родителя.

<?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. Протестировано, но не слишком много. Надеюсь, это поможет.

Ответ 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.

Я по-прежнему считаю, что проще организовать ваши представления и расширить их, вместо динамического прохождения.

Edit:

Здесь - это еще один способ. Но не проверял последнюю версию Laravel.

На ваш взгляд:

@extends($view)

и в контроллере:

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

Ответ 3

Я предлагаю использовать laravel blade stacks. Ссылка: https://laravel.com/docs/5.3/blade#stacks

Blade позволяет вам нажимать на именованные стеки, которые могут быть отображены где-то еще в другом представлении или макете.

Поэтому вместо расширения 'foo' просто нажмите "foo", используя стеки.

Вот некоторые ссылки и обсуждение для вашей справки:

В чем разница между секцией и стеком в клике?

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