gpt4 book ai didi

php - 在 Laravel 4 中缓存 View 输出

转载 作者:可可西里 更新时间:2023-10-31 22:53:16 32 4
gpt4 key购买 nike

我知道 Blade 已经为所有 Blade View 缓存了编译后的 PHP,但我想更进一步。我正在处理的一个网站被模块化为组件 View ,然后在默认 Controller 中拼凑在一起。每个“小部件”都有自己的 View ,很少更改内容(少数频繁更新的除外)。因此,我想缓存这些很少更改的 View 的 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'));
});

不幸的是,View::loader 在 Laravel 4 中完全消失了。当深入挖掘 \Illuminate\View\View\Illuminate\View\Environment,我发现每个 View 都会调度一个名为 "composing: {view_name}" 的事件。监听此事件会在每个 View 渲染时提供 View 名称和传递给它的数据,但是从回调返回的效果与 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);

以上并没有规避正常的 View 包含和渲染过程。

那么如何绕过正常的 View 渲染并从此组合事件返回缓存的内容呢?目前在 Laravel 中是否可能没有一些丑陋的 hackery?

最佳答案

快速而肮脏

好吧,我相信您知道,一种选择是在呈现 View 时将项目缓存在 Controller 内。我怀疑您不想这样做,因为从长远来看,它的可维护性较差。

更易于维护(?)的方法

但是,如果 View 加载器/渲染器没有在您想要的地方触发事件,您可以创建一个。因为 Laravel 4 中的每个包/库都是在 App 容器中设置的,所以你实际上可以用自己的库替换 View 库。

我将采取的步骤是:

  1. 创建一个库/包。目标是创建一个扩展 Laravel View 逻辑的类。看完之后,你可能想扩展 this one - 这是View外观
  2. 如果您用自己的 View 外观扩展了外观(也就是如果我在第 1 步中对文件的假设是正确的),那么您只需要替换 alias for Viewapp/config/app.php 中使用你自己的。

编辑 - 我玩了一下。虽然我不一定同意缓存 View 结果,而不是缓存 sql 查询或“更重的提升”,但这是我在 Laravel 4 中的做法:

Laravel 4 中的 View 渲染不会触发让我们缓存 View 结果的事件。以下是我在该功能中添加缓存 View 结果的方式。

You may want to consider the ramifications of caching a view's result. For instance, this doesn't get around doing the hard work of talking to a datbase to get the data needed for the view. In any case, this gives a good overview on extending or replacing core items.

首先,创建一个包并设置它的自动加载。我将使用命名空间 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 facade。在我们的例子中,这意味着我们将扩展 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 类作为 Facade。我有一篇关于 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'; }

}

然后,创建服务提供者,它将告诉 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 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,例如,让你define controllers as servers . Zend 有(曾经?)Action Stacks 的概念,它让你

... effectively help you create a queue of [controller] actions to execute during the request.

也许您想在 Laravel 中探索这种可能性,并缓存这些“操作”的结果(与直接缓存 View 相比)。

只是一个想法,不是推荐。

关于php - 在 Laravel 4 中缓存 View 输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17460157/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com