in Laravel 5 I need to amend a view content at runtime before compilation by adding this string: "@extends(foo)"
note: changing the view file content is not an option
so the process will be something like (each time a view is called)
I have tried using viewcomposer and middleware with no luck
here is my composer service provider:
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()
{
//
}
}
and here is my view middleware try (in middleware i was able to amend view content after compilation :( )
<?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;
}
}
Thanks
Update: what i need to accomplish is to extending views with layouts based on their parent directories
for example my view directory have the following structure
I need the view "controlpanel.blade.php" to have the layout "layout/admin.blade.php" because its parent folder is called "admin"
-view
|--pages
|--admin
|--controlpanel.blade.php
|--layouts
|--admin.blade.php
Views in Laravel are created in the resources/views folder. You can change base path for views by editing config/view. php file and changing `realpath(base_path('resources/views'))` to the new location for the views.
Views are stored in the resources/views directory. return view('greeting', ['name' => 'James']); }); As you can see, the first argument passed to the view helper corresponds to the name of the view file in the resources/views directory.
Blade is the simple, yet powerful templating engine that is included with Laravel. Unlike some PHP templating engines, Blade does not restrict you from using plain PHP code in your templates.
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.
Its not easy task. You need to replace Laravel's blade compiler class. It should take main layout from current view path instead of from @extends directive.
config/app.php: remove original service provider
Illuminate\View\ViewServiceProvider::class
add yours
App\Providers\BetterViewServiceProvider::class
In your service provider app/BetterViewServiceProvider.php the only important thing is to call \App\BetterBladeCompiler instead of original Illuminate\View\Compilers\BladeCompiler, the rest method is copied from 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']);
});
}
}
And now in app\BetterBladeCompiler.php override compileExtends methods and change it behaviout in this way that read current path and insert last directory before view file to expression that will be interpreted by other Laravel files.
<?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 '';
}
}
Code from Laravel 5.2. Tested but not too much. I hope it helps.
If you want to 'dynamically' extend the views here is a way:
$view = 'foo'; // view to be extended
$template = view('home')->nest('variable_name', $view, ['data' => $data]);
return $template->render();
And in your view:
@if (isset($variable_name))
{!! $variable_name !!}
@endif
This worked for me in Laravel 5.2.
I still think it is easier to organize your views and have them extend the corresponding layouts instead of dynamically passing.
Edit:
Here is another way. But did not check in the latest version of the Laravel.
In your view:
@extends($view)
and in controller:
$view = 'foo';
return view('someview', compact('view'));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With