在 Laravel 4 中缓存视图输出

2024-02-14

我知道 Blade 已经缓存了所有 Blade 视图的已编译 PHP,但我想更进一步。我正在开发的一个网站被模块化为组件视图,然后在默认控制器中拼凑在一起。每个“小部件”都有自己的视图,很少更改内容(少数频繁更新的除外)。因此,我想缓存这些很少更改的视图的 HTML 输出,以防止在每次页面加载时对它们进行评估。

在 Laravel 3 中我们可以这样做(信用 Laravel 论坛 http://forums.laravel.io/viewtopic.php?id=2277):

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 and \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 中是否有可能没有一些丑陋的黑客行为?


又快又脏

好吧,我相信您知道,一种选择是在渲染视图时将项目缓存在控制器内。我怀疑你不想这样做,因为从长远来看它的可维护性较差。

更可维护(?)的方法

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

我要采取的步骤是:

  1. 创建一个库/包。目标是创建一个扩展 Laravel 视图逻辑的类。看完之后,您可能想要扩展this one https://github.com/laravel/framework/blob/master/src/Illuminate/View/Environment.php- 这是View facade
  2. 如果您用自己的视图外观扩展(也就是说,如果我在步骤 1 中对文件的假设是正确的),那么您只需要替换视图的别名 https://github.com/laravel/laravel/blob/master/app/config/app.php#L180 in app/config/app.php与你自己的。

编辑-我玩了一下这个。虽然我不一定同意缓存 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正面。在我们的例子中,这意味着我们将延长照明\视图\环境 https://github.com/laravel/framework/blob/master/src/Illuminate/View/Environment.php.

在此类中,我们将获取正在呈现的视图的结果,并添加一些逻辑来缓存(或不缓存)它。这是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 工作。我有一篇关于创建 Laravel 外观 http://fideloper.com/create-facade-laravel-4。在这种情况下,如何实现这一点的方法如下:

为我们的新环境创建立面。我们将其命名为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 class.

<?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 的视图外观。编辑app/config/app.php:

添加服务提供商:

'providers' => array(

    // Other providers

    'Fideloper\View\ViewServiceProvider',

),

用我们自己的视图外观替换:

'aliases' => array(

    // Other Aliases

    //'View'            => 'Illuminate\Support\Facades\View',
    'View'            => 'Fideloper\View\ViewFacade',

),

然后你就可以在其中使用你想要的任何逻辑View::make() method!

Finally

值得注意的是,每个 Web 请求的多个“请求”中都会加载一些模式。以 Symfony 为例,让您将控制器定义为服务器 http://symfony.com/doc/current/cookbook/controller/service.html。 Zend 有(有?)一个 Action Stacks 的概念,它让你

...有效地帮助您创建要在请求期间执行的[控制器]操作队列。

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

只是一个想法,不是建议。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Laravel 4 中缓存视图输出 的相关文章

随机推荐

  • 为什么 IntelliSense 无法将我的查询所选项目识别为元素?

    Problem 我试图弄清楚为什么当我使用以下命令访问 HTML 元素时 VSCode 的 IntelliSense 不会建议元素对象属性 document querySelector 每当我使用document querySelector
  • 重试 Javascript.Promise.reject 有限次数或直到成功

    我有一个函数说myMainFunction从客户端调用 然后调用mypromisified功能 设想 mypromisified函数可能会间歇性失败 我需要延迟 以指数增长 调用此函数 直到成功或达到最大尝试次数 到目前为止我所拥有的 以下
  • icmp 端口不可达错误消息

    我正在将 UDP 数据包从一台 PC 发送到另一台 PC 我正在使用 Wire Shark 观看整个活动 我注意到有一段时间数据包从一个系统到另一个系统的传输很顺利 然后突然间ICMP有错误的数据包 port unreachable 开始出
  • Bash 脚本中的这一行是如何工作的?

    我试图弄清楚顶部的某一行代码是如何BASH 手册页选项卡补全脚本 https github com scop bash completion blob 52315ef2ceb3f8e6b7fe45a09f8df24b73394da4 com
  • 是否可以通过 GitHub 的 Web 界面恢复提交

    我正在 Chromebook 上教授 HTML 课程 我们使用 GitHub 进行修订控制 我想向我的学生展示如何恢复提交 由于我们在 Chromebook 上没有 shell 访问权限 因此我希望通过 GitHub 网站找到一种在线执行此
  • Laravel 5.2 - pluck() 方法返回数组

    我正在尝试升级我的项目 L5 1 gt L5 2 在升级指南 http laravel com docs 5 2 upgrade upgrade 5 2 0有一件事我不清楚 The listsCollection 上的方法 查询生成器和 E
  • 如何使用 datetime.time 绘图

    我有 HH MM SS 格式的时间戳列表 并希望使用 datetime time 绘制某些值 看来 python 不喜欢我这样做的方式 有人可以帮忙吗 import datetime import matplotlib pyplot as
  • 我如何告诉 Masonry 组件它的单元格已经改变了高度?

    我有一个反应组件 它以网格模式显示一维项目列表 每个项目都具有相同的宽度和高度 并且它们位于三列内 可能有很多这样的东西 所以我决定使用 Masonry 组件来尝试一下 React virtualized 该组件似乎是专门为这个用例而编写的
  • 如何在 C# 中创建 X509Certificate2 时更改颁发者名称

    我正在我的 C net 应用程序中创建 X509Certificate2 证书 创建证书时 如何设置颁发者名称 目前发行人名称与主体名称相同 请帮忙 Hmm 终于我用了充气城堡 dll创建证书 使用它 有一种方法可以设置颁发者名称 这是要生
  • --ntasks 或 -ntasks 在 SLURM 中起什么作用?

    我正在使用SLURM http slurm schedmd com 使用一些计算集群 它有 ntasks or n 我显然已经阅读了它的文档 http slurm schedmd com sbatch html http slurm sch
  • 为什么清空 NavigationStack 路径后对象仍在内存中?

    我正在尝试实现一个协调器来管理流程 状态存储在 CoordinatorStore 内 有 2 个用于管理流程的 Published 属性 这screen属性控制当前显示哪个视图以及path控制堆栈视图的导航堆栈 实施细节可以在下面找到 根据
  • grunt-contrib-jshint 忽略没有效果

    我想排除libs目录免于被检查 然而 ignores in options并种植了 jshintignore项目目录中的文件不会生成libs被排除在外 jshint options smarttabs true ignores public
  • 让 Sphinx 替换文档字符串文本

    我正在 Sphinx 中记录类似于以下内容的代码 class ParentClass object def init self pass def generic fun self Call this function using run P
  • Zend框架中的内连接

    我想在两个表之间进行内连接 访问表有 访问id target 报告表有 rep id visit id 每次访问都有很多报告 我想选择所有指定访问目标的报告 我这样做但它不起作用 db Zend Db Table getDefaultAda
  • Mercurial 显示文件修改不正确

    当我克隆 Mercurial 存储库时 它通常会显示文件已被修改 而实际上尚未修改 当我执行以下步骤时可能会发生这种情况 hg clone
  • 片段中的列表视图不起作用

    这是我的片段代码 public class LeftFragment extends ListFragment ArrayList
  • 带参数的装饰器[重复]

    这个问题在这里已经有答案了 代码如下 def my dec func def wrap w t func w return t 4 return wrap my dec def testing n return n new testing
  • C# Web 浏览器选择列表项单击

    我正在尝试使用以下方法从选择列表框中选择项目 var elements webBrowser1 Document GetElementsByTagName select foreach HtmlElement element in elem
  • 什么相当于 C# 中的 Microsoft.VisualBasic.Collection?

    我有一个方法 它需要一个存储过程名称和一个Microsoft VisualBasic Collection http msdn microsoft com en us library microsoft visualbasic collec
  • 在 Laravel 4 中缓存视图输出

    我知道 Blade 已经缓存了所有 Blade 视图的已编译 PHP 但我想更进一步 我正在开发的一个网站被模块化为组件视图 然后在默认控制器中拼凑在一起 每个 小部件 都有自己的视图 很少更改内容 少数频繁更新的除外 因此 我想缓存这些很