又快又脏
好吧,我相信您知道,一种选择是在渲染视图时将项目缓存在控制器中。我怀疑您不想这样做,因为从长远来看,它的可维护性较差。
更可维护的(?)方法
但是,如果 View loader/renderer 没有触发您想要的事件,您可以创建一个。因为 Laravel 4 中的每个包/库都是在 App 容器中设置的,所以您实际上可以将 View 库替换为您自己的。
我将采取的步骤是:
- 创建一个库/包。目标是创建一个扩展 Laravel 视图逻辑的类。看过之后,你可能想扩展这个——这是
View
门面
- 如果您用自己的方式扩展了 View 外观(也就是如果我在步骤 1 中对文件的假设是正确的),那么您只需将View in的别名替换为
app/config/app.php
您自己的。
编辑-我玩了一下。虽然我不一定同意缓存视图结果,而不是缓存 sql 查询或“更重的提升”,但这是我在 Laravel 4 中将如何做到这一点:
Laravel 4 中的视图渲染不会触发让我们缓存视图结果的事件。以下是我添加该功能以缓存视图结果的方式。
您可能需要考虑缓存视图结果的后果。例如,这并没有绕过与数据库对话以获取视图所需数据的艰苦工作。无论如何,这很好地概述了扩展或替换核心项目。
首先,创建一个包并设置它的自动加载。我将使用命名空间Fideloper\View
。它的自动加载composer.json
将如下所示:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php"
],
"psr-0": {
"Fideloper": "app/"
}
},
接下来,创建一个类来替换View
外观。在我们的例子中,这意味着我们将扩展Illuminate\View\Environment。
在这个类中,我们将获取视图渲染的结果并添加一些逻辑来缓存(或不缓存)它。这里是Fideloper/View/Environment.php
:
<?php namespace Fideloper\View;
use Illuminate\View\Environment as BaseEnvironment;
use Illuminate\View\View;
class Environment extends BaseEnvironment {
/**
* Get a evaluated view contents for the given view.
*
* @param string $view
* @param array $data
* @param array $mergeData
* @return \Illuminate\View\View
*/
public function make($view, $data = array(), $mergeData = array())
{
$path = $this->finder->find($view);
$data = array_merge($mergeData, $this->parseData($data));
$newView = new View($this, $this->getEngineFromPath($path), $view, $path, $data);
// Cache Logic Here
return $newView;
}
}
所以,这就是你大部分工作的地方——填写// Cache Logic Here
. 但是,我们还有一些管道工作要做。
接下来,我们需要设置我们的新Environment
类作为一个门面工作。我有一篇关于创建 Laravel 外观的博客文章。以下是在这种情况下如何实现这一点:
为我们的新环境创建外观。我们将fideloper.view
在代码中命名它。
<?php namespace Fideloper\View;
use Illuminate\Support\Facades\Facade;
class ViewFacade extends Facade {
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor() { return 'fideloper.view'; }
}
然后,创建服务提供者,它会告诉 Laravel 在fideloper.view
被调用时要创建什么。请注意,这需要模仿Illuminate\View\ViewServiceProvider
创建扩展Environment
类的功能。
<?php namespace Fideloper\View;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider {
public function register()
{
$this->app['fideloper.view'] = $this->app->share(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 Environment($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;
});
}
}
最后,我们需要将所有这些连接在一起,并告诉 Laravel 加载我们的服务提供者并用我们自己的替换 Illuminate 的 View 外观。编辑app/config/app.php
:
添加服务提供者:
'providers' => array(
// Other providers
'Fideloper\View\ViewServiceProvider',
),
用我们自己的替换 View 门面:
'aliases' => array(
// Other Aliases
//'View' => 'Illuminate\Support\Facades\View',
'View' => 'Fideloper\View\ViewFacade',
),
然后,您将能够在该View::make()
方法中使用您希望的任何逻辑!
最后
值得注意的是,每个 Web 请求都需要在多个“请求”中加载一些模式。例如,Symfony 让我们将控制器定义为服务器。Zend 有(有?)Action Stacks 的概念,它让你
...有效地帮助您创建在请求期间执行的 [控制器] 操作队列。
也许您想在 Laravel 中探索这种可能性,并缓存这些“动作”的结果(而不是直接缓存视图)。
只是一个想法,不是推荐。