我知道Blade已经为所有的blade视图缓存了编译后的PHP,但我想更进一步。我正在工作的一个网站被模块化到组件视图中,然后在默认控制器中拼接在一起。每个“小部件”都有自己的视图,很少更改内容(除了少数频繁更新的小部件)。因此,我想缓存这些很少更改的视图的HTML输出,以防止在每次加载页面时都对它们进行评估。
在Laravel 3中,我们可以这样做(credit Laravel forums):
Event::listen(View::loader, function($bundle, $view)
{
return Cache::get($bundle.'::'.$view, View::file($bundle, $view,
Bundle::path($bundle).'view'));
});
不幸的是,在Laravel 4中,View::loader
完全消失了。在深入研究\Illuminate\View\View
和\Illuminate\View\Environment
时,我发现每个视图都会分派一个名为"composing: {view_name}"
的事件。侦听此事件会在每个视图渲染时提供视图名称和传递给它的数据,但是从回调返回的效果与Laravel 3中的效果不同:
Event::listen('composing: *', function($view) {
if(!in_array($view->getName(), Config::get('view.alwaysFresh'))) {
// Hacky way of removing data that we didn't pass in
// that have nasty cyclic references (like __env, app, and errors)
$passedData = array_diff_key($view->getData(), $view->getEnvironment()
->getShared());
return Cache::forever($view->getName() . json_encode($passedData), function() {
return 'test view data -- this should appear in the browser';
});
}, 99);
以上操作不会绕过正常的视图包含和渲染过程。
那么,如何绕过正常的视图呈现,并从这个合成事件返回缓存的内容呢?目前在Laravel中有没有可能没有一些丑陋的黑客行为?
发布于 2013-07-07 00:34:50
快速和肮脏的
好的,我相信你知道,一种选择是在呈现视图时在控制器中缓存这些项。我怀疑您不想这样做,因为从长远来看,它的可维护性较差。
更具可维护性(?)方法
然而,如果视图加载器/渲染器没有在你想要的地方触发事件,你可以创建一个。因为Laravel 4中的每个包/库都是在App容器中设置的,所以您实际上可以用自己的View库替换它。
我将采取的步骤是:
View
facade app/config/app.php
中的alias for View。编辑--我用了一点这个。虽然我不一定同意缓存一个视图结果,而不是缓存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。
在这个类中,我们将获取呈现的View的结果,并添加一些逻辑来缓存(或不缓存)它。这是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
类设置为外观。我有一篇关于creating Laravel facades的博客文章。下面是在这种情况下如何实现这一点:
为我们的新环境创建外观。我们将在代码中将其命名为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'; }
}
然后,创建服务提供者,它将在调用fideloper.view
时告诉Laravel要创建什么。请注意,这需要模拟用于创建扩展Environment
类的Illuminate\View\ViewServiceProvider
的功能。
<?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 facade。编辑app/config/app.php
添加服务提供商:
'providers' => array(
// Other providers
'Fideloper\View\ViewServiceProvider',
),
将View facade替换为我们自己的:
'aliases' => array(
// Other Aliases
//'View' => 'Illuminate\Support\Facades\View',
'View' => 'Fideloper\View\ViewFacade',
),
然后,您将能够在View::make()
方法中使用任何逻辑!
最终
值得注意的是,有一些模式可以加载到每个web请求的多个“请求”中。举个例子,Symfony,‘s’s you define controllers as servers。Zend有(had?)Action Stacks的概念,它可以让您
...有效地帮助您创建要在请求期间执行的控制器操作队列。
也许您想在Laravel中探索这种可能性,并缓存这些“操作”的结果(与直接缓存视图相比)。
这只是一个想法,不是一个建议。
发布于 2015-05-04 18:54:01
在Laravel中有一个用于缓存视图/部件的库- Flatten。
它是一个强大的缓存系统,用于在运行时缓存页面。它的作用非常简单:您告诉他要缓存哪个页面,何时刷新缓存,然后Flatten会处理所有这些事情。它会悄悄地将你的页面展平为普通的HTML并存储它们。如果用户访问一个已经被扁平化的页面,那么所有的PHP都会被劫持,以显示一个简单的HTML页面。这将极大地提高应用程序的速度,因为页面的缓存只有在页面所显示的数据发生更改时才会刷新。
通过artisan flatten:build
命令在应用程序中缓存所有授权页面。它将爬行你的应用程序,从一个页面到另一个页面,缓存你允许他访问的所有页面。
法拉盛
有时,您可能希望刷新特定的页面或模式。例如,如果您缓存了用户的配置文件,那么当用户编辑其信息时,您可能需要刷新这些配置文件。您可以通过以下方法执行此操作:
// Manual flushing
Flatten::flushAll();
Flatten::flushPattern('users/.+');
Flatten::flushUrl('http://localhost/users/taylorotwell');
// Flushing via an UrlGenerator
Flatten::flushRoute('user', 'taylorotwell');
Flatten::flushAction('UsersController@user', 'taylorotwell');
// Flushing template sections (see below)
Flatten::flushSection('articles');
https://stackoverflow.com/questions/17460157
复制