How to override View :: make () in Laravel 4?
I would like to override the default method View::make()
in Laravel that can be used to return the view to the user.
(I think) I already figured out that this method is stored internally Illuminate\View\Factory.php
and I was reading about the IoC container trying to get it to work using some similar tutorials , but it just won't work.
I have already created a file App\Lib\MyProject\Extensions\View\Factory.php
containing the following code:
<?php namespace MyProject\Extensions\View;
use Illuminate\View\Factory as OldFactory;
class Factory extends OldFactory {
public static function make() {
// My own implementation which should override the default
}
}
where the folder is MyProject
automatically loaded by Composer. But I don't know how to use this "modified" version of the class Factory
whenever a static method is called View
(in particular View::make()
). Some help would be great!
Thank!
source to share
Calling View::make
in Laravel talks about calling the facade View
. Facades provide global static access to a service in a service container. Step 1 - Finding the actual class View
points to
#File: app/config/app.php
'aliases' => array(
'View' => 'Illuminate\Support\Facades\View',
)
This means it View
is a class alias Illuminate\Support\Facades\View
. If you look at the sourceIlluminate\Support\Facades\View
#File: vendor/laravel/framework/src/Illuminate/Support/Facades/View.php
class View extends Facade {
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor() { return 'view'; }
}
You can see that the accessory is the service facade View
. This means that the call
View::make...
is (more or less) equivalent to calling
$app = app();
$app['view']->make(...
That is, the facade provides access to the service View
in the service container. To replace another class, all you have to do is bind the other object as a service View
. Laravel provides a method extend
for this.
App::extend('view', function(){
$app = app();
// Next we need to grab the engine resolver instance that will be used by the
// environment. The resolver will be used by an environment to get each of
// the various engine implementations such as plain PHP or Blade engine.
$resolver = $app['view.engine.resolver'];
$finder = $app['view.finder'];
$env = new \MyProject\Extensions\View($resolver, $finder, $app['events']);
// We will also set the container instance on this view environment since the
// view composers may be classes registered in the container, which allows
// for great testable, flexible composers for the application developer.
$env->setContainer($app);
$env->share('app', $app);
return $env;
});
Note that this is more than just creating an object. We need to create an instance in the same way that we were created and bound to the original view service (usually with bind
or bindShared
). You can find this code here
#File: vendor\laravel\framework\src\Illuminate\View\ViewServiceProvider.php
public function registerFactory()
{
$this->app->bindShared('view', function($app)
{
// Next we need to grab the engine resolver instance that will be used by the
// environment. The resolver will be used by an environment to get each of
// the various engine implementations such as plain PHP or Blade engine.
$resolver = $app['view.engine.resolver'];
$finder = $app['view.finder'];
$env = new Factory($resolver, $finder, $app['events']);
// We will also set the container instance on this view environment since the
// view composers may be classes registered in the container, which allows
// for great testable, flexible composers for the application developer.
$env->setContainer($app);
$env->share('app', $app);
return $env;
});
}
You can check if your linking worked with code like this
var_dump(get_class(app()['view']));
You should see your class name. Once you are sure that the binding is "taken", you can override any methods you want.
source to share