ZF2 上的渲染问题,尝试渲染布局以获取 html 代码


Rendering issue on ZF2, trying to render layout to get html code

我在使用PhpRenderer时遇到了问题,让我们从上下文开始。我必须生成一堆静态页面来缓存它们(使用文件系统适配器的缓存存储)。因此,我在EVENT_ROUTE上连接了一个事件来提供静态页面(如果存在),并在EVENT_FINISH上连接一个事件以获取响应内容并将其写入缓存文件。它工作得很好。

我的问题是,我想在导航之前生成这些页面(我有大约 300 万个页面要生成)。我的想法是创建一个可以在CLI中调用的控制器,以便能够安排庞大的任务。因此,在我的第二个控制器中,我调用返回我感兴趣的 ViewModel 的控制器,构建渲染器,并呈现我的操作 ViewModel 和布局以获取页面的整个 HTML。

这是代码:

public static function GetStaticResponse(ServiceManager $sm, AbstractActionController $controller, array $routeParams){
    $event = new MvcEvent();
    $request = new Request();
    // $controller = new $controller();
    $router = $sm->get('Router');
    // Test values!!!
    // $routeMatch = new RouteMatch(array('controller' => 'index', 'action' => 'showad', 'ad_id' => '1002293747'));
    // Test values end !!
    $routeMatch = new RouteMatch($routeParams);
    $event->setRouter($router);
    $event->setRouteMatch($routeMatch);
    $controller->setEvent($event);
    $pluginManager = $sm->get('ControllerPluginManager');
    $controller->setServiceLocator($sm);
    $controller->setPluginManager($pluginManager);
    $view = $controller->dispatch($request);
    $config = $sm->get('Config');
    $renderer = new PhpRenderer($config);
    $map = new TemplateMapResolver(
        $config['view_manager']['template_map']
    );
    $renderer->setResolver($map);
    $renderer->setHelperPluginManager($sm->get('ViewHelperManager'));
    $view->setTemplate('showad');
    $content = $renderer->render($view);
    $renderer = new PhpRenderer($config);
    $map = new TemplateMapResolver(
        $config['view_manager']['template_map']
    );
    $renderer->setResolver($map);
    $renderer->setHelperPluginManager($sm->get('ViewHelperManager'));
    $viewLayout = new ViewModel();
    $viewLayout->setTemplate('layout/layout');
    $viewLayout->setVariables(array("content" => $content));
    $render = $renderer->render($viewLayout);
    unset($event, $request, $router, $routeMatch, $controller, $pluginManager, $view, $config, $renderer, $content, $viewLayout);
    return $render;
}

当我只执行一次时,此方法工作正常。当我在循环中再次调用此方法时,渲染器似乎具有一些静态属性,并且每当布局调用"headTitle"或"headLink"等帮助程序时,标题和链接都会一次又一次地附加。

例如:第一个循环

<!DOCTYPE html><html lang="fr">
  <head>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
    <link rel="icon" type="image/ico" href="http://apte.local/images/favicon.ico">
            <title>title</title>            
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- Le styles -->
    <link href="http://apte.local/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
<link href="http://apte.local/css/style.min.css" media="screen" rel="stylesheet" type="text/css">
<link href="http://apte.local/js/jquery/css/ui-lightness/jquery-ui.css" media="screen" rel="stylesheet" type="text/css">
    <!-- Scripts -->

第二循环:

<!DOCTYPE html><html lang="fr">
  <head>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
    <link rel="icon" type="image/ico" href="http://apte.local/images/favicon.ico">
            <title>title - title</title><!-- title generated with headTitle -->            
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- in layout headMeta is used to generate meta -->
    <!-- Le styles -->
    <link href="http://apte.local/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
<link href="http://apte.local/css/style.min.css" media="screen" rel="stylesheet" type="text/css">
<link href="http://apte.local/js/jquery/css/ui-lightness/jquery-ui.css" media="screen" rel="stylesheet" type="text/css">
<link href="http://apte.local/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon"> <!-- in layout headLink helper is used to generate the link -->
    <!-- Scripts -->

我不知道我的想法是否正确,我认为使用与单元测试相同的逻辑可以完成这项工作,我错过了什么吗?

我想知道是否有办法触发我已经编码并且在 http 模式下工作正常的事件。

(我已经测试过在EVENT_DISPATCH上连接回声"测试",但我的事件只触发了一次,$controller->dispatch(...) 不会触发当前事件管理器的调度事件。

如果有人有想法,或者遇到过类似的案例,我很乐意阅读您如何解决这个问题。

好吧,我找到了解决这个问题的方法,实际上它来自插件headMeta,headTitle,这些插件使用缓存来存储所有添加的条目(附加,前置或设置)。当实例化新的渲染器或获取当前时,缓存不会重置,当然,在第二次渲染时,更多的条目会添加到当前插件缓存中......所以每次渲染后,都必须清除缓存,以避免多个标题、元等......

我的代码来解决这个问题In ConsoleController::buildStaticCacheAction()

// Following code is in a loop
// Dispatch to get the ViewModel
$view = $this->forward()->dispatch('Application'Controller'Index', array("controller" => "index", "action" => "showad", "ad_id" => $current['adId']));
// Getting renderer
$renderer = $this->getServiceLocator()->get('ViewManager')->getRenderer();
// Render
$html = $renderer->render($view);
//Clear head plugins cache
$renderer->headTitle()->setContainer(new Container());
$renderer->headMeta()->setContainer(new Container());
$renderer->headLink()->setContainer(new Container());

我猜$view->setTemplate('showad')以某种方式搞砸了它。从调度中获得响应后,您可以将其设置为嵌套的 ViewModel 或仅作为新 ViewModel() 的变量,对吗?

关于生成请求,

您可以生成控制台请求并创建控制台感知控制器,而不是像单元测试那样引导。