通过控制视图模板路劲来动态切换主题
App::before(function($request){ $paths = Terminal::isMobile() ? array(__dir__.'/views/mobile') : array(__dir__.'/views/pc'); View::setFinder( new Illuminate\View\FileViewFinder(App::make('files'),$paths));});
首先说说为什么直接通过修改配置不行
public function registerViewFinder() { $this->app->bindShared('view.finder', function($app) { $paths = $app['config']['view.paths']; return new FileViewFinder($app['files'], $paths); }); }
这段是用于注册FileViewFinder服务的代码,为什么要说这个服务,因为我们的View服务是依赖他来获取视图路劲的
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; }); }
视图的注册是返回一个工厂类,之后直接通过LOC容器去获取FileViewFinder:$finder = $app['view.finder'];
在理解这段代码之前我们需要先理解bindShared和不同的bind有何不同
public function share(Closure $closure) { return function($container) use ($closure) { // We'll simply declare a static variable within the Closures and if it has // not been set we will execute the given Closures to resolve this value // and return it back to these consumers of the method as an instance. static $object; if (is_null($object)) { $object = $closure($container); } return $object; }; } /** * Bind a shared Closure into the container. * * @param string $abstract * @param \Closure $closure * @return void */ public function bindShared($abstract, Closure $closure) { $this->bind($abstract, $this->share($closure), true); }
从这里可以看出bindShared不仅会向LOC容器注册,而且还会执行闭包函数,直接获取返回对象,也就是说当我在使用View::make()的时候这个对象已经存在了,并且服务的注册是在App::before之前的
通过上面的分析我们可以知道,当我们在App::before事件中直接修改视图路劲时,我们的视图服务和FileViewFinder是不会重新实例化的,所以他们获取的view.paths还是最开始定义的,也就是说我们在使用视图服务时想要改变路劲就需要重新设置我们的FileViewFinder服务,也就是最上面看到的代码。