Php 在Laravel 4中缓存视图输出

Php 在Laravel 4中缓存视图输出,php,caching,view,laravel,blade,Php,Caching,View,Laravel,Blade,我知道Blade已经为所有Blade视图缓存了编译后的PHP,但我想更进一步。我正在处理的网站被模块化为组件视图,然后在默认控制器中拼接在一起。每个“小部件”都有自己的视图,很少更改内容(少数经常更新的除外)。因此,我想缓存这些很少变化的视图的HTML输出,以防止在每次加载页面时对它们进行评估 在Laravel 3中,我们可以这样做(): 不幸的是,View::loader在Laravel4中完全消失了。在深入研究\illumb\View\View和\illumb\View\Environmen

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

在Laravel 3中,我们可以这样做():

不幸的是,
View::loader
在Laravel4中完全消失了。在深入研究
\illumb\View\View
\illumb\View\Environment
时,我发现每个视图都发送一个名为
“composing:{View\u 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 4中的每个包/库都设置在应用程序容器中,所以您实际上可以用自己的视图库替换视图库

我将采取的步骤是:

  • 创建库/包。目标是创建一个扩展Laravel视图逻辑的类。看了之后,您可能想要扩展-这是
    视图
    外观
  • 如果您用自己的扩展了视图外观(如果我在步骤1中对文件的假设是正确的话),那么您只需要用自己的替换
    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/"
        }
    },
    
    接下来,创建一个类来替换
    视图
    外观。在我们的情况下,这意味着我们将扩展

    在这个类中,我们将获取呈现视图的结果,并向缓存(或不缓存)视图添加一些逻辑。下面是
    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;
        }
    
    }
    
    然后,创建服务提供商,当调用
    fideloper.view
    时,该服务提供商将告诉Laravel要创建什么。请注意,这需要模拟
    照明\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;
            });
        }
    
    }
    
    将视图立面替换为我们自己的:

    'aliases' => array(
    
        // Other Aliases
    
        //'View'            => 'Illuminate\Support\Facades\View',
        'View'            => 'Fideloper\View\ViewFacade',
    
    ),
    
    然后,您将能够在
    View::make()
    方法中使用您想要的任何逻辑

    最后

    值得注意的是,有一些模式可以加载到每个web请求的多个“请求”中。例如,Symfony,让我们来看看你。Zend有一个动作堆栈的概念,它让你

    。。。有效地帮助您创建在请求期间执行的[controller]操作队列

    也许您希望在Laravel中探索这种可能性,并缓存这些“操作”的结果(而不是直接缓存视图)


    只是一个想法,不是建议

    有一个库用于缓存Laravel中的视图/零件(不仅仅是)-展平

    它是一个强大的缓存系统,用于在运行时缓存页面。它所做的很简单:你告诉他要缓存哪个页面,何时刷新缓存,然后由flant处理所有的事情。它会悄悄地将您的页面扁平化为纯HTML并存储它们。如果用户访问一个已经被压平的页面,那么所有的PHP都会被提升到显示一个简单的HTML页面。这将大大提高应用程序的速度,因为页面的缓存只有在对其显示的数据进行更改时才会刷新

    通过
    artisan flant: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');
    

    链接到-

    请问您这样做是否避免了视图数据的重新创建?即使视图结果本身保存在缓存中,您仍然需要点击数据库来创建视图吗?您可能会更幸运地缓存数据库命中的结果,等等。对于服务提供商和Facades的详细指南,可以使用+1(如果可以的话,我会使用+2或+3!)。我一直在避免读关于他们的书,但你却说服了我。这是使用它们的一个很好的例子,也是扩展Laravel功能的一个很好的起点。谢谢回答你的问题
    'providers' => array(
    
        // Other providers
    
        'Fideloper\View\ViewServiceProvider',
    
    ),
    
    'aliases' => array(
    
        // Other Aliases
    
        //'View'            => 'Illuminate\Support\Facades\View',
        'View'            => 'Fideloper\View\ViewFacade',
    
    ),
    
    // 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');