6

我刚刚开始全神贯注于缓存。我有一个简单的 indexAction() 可以获取所有给定的数据集。我的做法是:

  • 检查现有键'controllername-index-index'
  • 如果存在:返回键的值
  • 如果存在,请执行正常操作并添加密钥

键中的值应该是将生成并填充我的数据的 ViewModel。

这是我到目前为止所做的:

<?php
public function indexAction()
{
    $sl = $this->getServiceLocator();
//  $cache = $sl->get('cache');
//  $key = 'kennzahlen-index-index';
//
//  if ($cache->hasItem($key)) {
//      return $cache->getItem($key);
//  }

    $viewModel = new ViewModel();
    $viewModel->setTemplate('kennzahlen/index/index');
    $entityService = $sl->get('kennzahlen_referenzwert_service');
    $viewModel->setVariable('entities', $entityService->findAll());

//  $cache->setItem($key, $viewModel);

    return $viewModel;
}

出于测试目的,缓存部分被注释掉了,但基本上这就是我所做的一切。缓存配置/服务如下所示:

<?php
'cache' => function () {
    return \Zend\Cache\StorageFactory::factory(array(
        'adapter' => array(
            'name' => 'filesystem',
            'options' => array(
                'cache_dir' => __DIR__ . '/../../data/cache',
                'ttl' => 100
            ),
        ),
        'plugins' => array(
            array(
                'name' => 'serializer',
                'options' => array(

                )
            )
        )
    ));
},

序列化和缓存工作得很好,但我对丢失的结果感到惊讶。根据 ZendDevelopersToolbar 告诉我的内容,没有缓存的时间范围在 1.8s 到 2.5s 之间。取消注释(启用)缓存部分并没有真正改善我页面的加载时间。

所以我的问题是:这种方法完全错误吗?是否有不同的、更快速的部件可以通过一些巧妙的配置技巧来保存?

我觉得 2 秒的页面加载时间肯定太慢了。考虑到大量数据,1s 对我来说是最大值,但肯定不会超过这个:S

所有帮助/提示/建议将不胜感激。提前致谢!

4

1 回答 1

17

一种选择是缓存页面的完整输出,例如基于路由匹配。您需要在路由和调度之间侦听已找到匹配的路由,然后采取相应的行动:

namespace MyModule;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        // A list of routes to be cached
        $routes = array('foo/bar', 'foo/baz');

        $app = $e->getApplication();
        $em  = $app->getEventManager();
        $sm  = $app->getServiceManager();

        $em->attach(MvcEvent::EVENT_ROUTE, function($e) use ($sm) {
            $route = $e->getRouteMatch()->getMatchedRouteName();
            $cache = $sm->get('cache-service');
            $key   = 'route-cache-' . $route;

            if ($cache->hasItem($key)) {
                // Handle response
                $content  = $cache->getItem($key);

                $response = $e->getResponse();
                $response->setContent($content);

                return $response;
            }
        }, -1000); // Low, then routing has happened

        $em->attach(MvcEvent::EVENT_RENDER, function($e) use ($sm, $routes) {
            $route = $e->getRouteMatch()->getMatchedRouteName();
            if (!in_array($route, $routes)) {
                return;
            }

            $response = $e->getResponse();
            $content  = $response->getContent();

            $cache = $sm->get('cache-service');
            $key   = 'route-cache-' . $route;
            $cache->setItem($key, $content);
        }, -1000); // Late, then rendering has happened
    }
}

第二个侦听器检查渲染事件。如果发生这种情况,响应的结果将被缓存。

这个系统(可能不是 100% 复制/粘贴,而是概念)之所以有效,是因为如果您Response在路由或调度事件期间返回 a,应用程序将短路应用程序流程并停止进一步触发侦听器。然后它将按原样提供此响应。

Bear in mind it will be the complete page (including layout). If you don't want that (only the controller), move the logic to the controller. The first event (now route) will be dispatch of the controller. Listen to that early, so the normal execution of the action will be omitted. To cache the result, check the render event for the view layer to listen to.

/update: I wrote a small module to use this DRY in your app: SlmCache

于 2012-12-08T15:45:31.330 回答