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