Warmup sitemap cache

Hello guys, maybe you can help…

We have a Controller (SitemapController) which loads a Sitemap page from a cache or if the page is not present in the cache it will be created.
To warm up / update the cache we call a method in a service (SitemapCacheService) via the command line (WarmupCommandController, php flow warmup:warmup). This service method calls action methods (like siteMapAction) in the SitemapController via an object manager to update the cache.
The problem is that we need to assign elements to the view via view->assign() and by calling the action methods via command line, the views are null.
We solved this by creating manually standalone views and assigning the updated values to them. The created views’ output is then persisted in the cache, which replaces the old.

Our question:
Is there a better, maybe more elegant way to call the action methods directly and avoiding “null” views and the need to create standalone views? Maybe by faking an action request instead ? How could we achieve this?

`<?php
namespace PROJECT\Main\Controller;

use TYPO3\Flow\Annotations as Flow;

class SitemapController extends \TYPO3\Flow\Mvc\Controller\ActionController {

/**
 * @var array
 * @Flow\InjectConfiguration("activePages")
 */
protected $activePages;

/**
 * @Flow\Inject
 * @var \PROJECT\Main\Service\Cache\SitemapCacheService
 */
protected $sitemapCacheService;

/**
 * @Flow\Inject
 * @var \PROJECT\Main\Domain\Repository\JobRepository
 */
protected $jobRepository;

/**
 * @Flow\Inject
 * @var \PROJECT\Main\Domain\Repository\ProjectRepository
 */
protected $projectRepository;

public function siteMapAction() {
    $this->setContentTypeXML();

    $output = $this->sitemapCacheService->getSitemap();

    if($output === false) {
        // cache is empty

        $view = $this->view;
        if ($view == null) {
            // $view is null when action is called from service
            $view = $this->createStandaloneView("SiteMapPages.xml");
        }

        // set cache
        $PagesArray = array();
        foreach ($this->activePages as $topic) {
            $PagesArray = array_merge($PagesArray, $topic);
        }

        $view->assign('Pages', $PagesArray);

        $output = $view->render();
        $this->sitemapCacheService->setSitemap($output);
    }

    return $output;
}

/************************************************
 * PRIVATE FUNCTIONS
 ***********************************************/

private function setContentTypeXML(){
    if($this->getControllerContext() == null){
        return;
    }
    $this->getControllerContext()->getResponse()->setHeader('Content-Type', 'application/xml');
}

/**
 * Creates manually a view, which can be filled and passed to the service for setting the cache
 *
 * @param $template
 * @return \TYPO3\Fluid\View\StandaloneView
 */
private function createStandaloneView($template){
    $view =  new \TYPO3\Fluid\View\StandaloneView();

    $request = $view->getRequest();
    $request->setControllerPackageKey('PROJECT.Main');

    $view->setFormat("xml");
    $view->setLayoutRootPath('resource://PROJECT.Main/Private/Layouts');
    $templatePathAndFilename = 'resource://PROJECT.Main/Private/Templates/Sitemap/' . $template;
    $view->setTemplatePathAndFilename($templatePathAndFilename);

    return $view;
}

}`

Hi @walter.laurito

Could you isolate the caching of the sitemap output, and then use a specific $viewFormatToObjectNameMap to return the xml ?

I think of something like (pure pseudo, copy/paste at own risk :wink: )

/** Iterate over whatever you need to output and create a data array and add it directly to the cache */
$sitemapCache->set('sitemap', $generatedSitemapData);

and have the warmup method fill that cache.

Inside your SitemapController get the cache and assign it.

$this->view->assign('pages', $sitemapCache->get('sitemap');

and use the $viewFormatToObjectNameMap property like described here in the doc (example with jsonview)

http://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/ModelViewController.html#json-view

and then create your own simple XML view that uses something like

$xml = new SimpleXMLElement('<root/>');
array_walk_recursive($assignedViewData, array ($xml, 'addChild'));

to render the sitemap output.

Remember to register the format in your Routes.yaml

1 Like