/** * Returns a rendered view. If we find html behind the given cache * it returns this directly. This is a couple os ms faster than `renderCached` * since the template engine is never used when there's a valid cache. * * Example: * * return $this->renderFullCached('myCache', 'plugin1/default.tpl', function(){ * return array('items' => heavyDbQuery()); * }); * * Note: The $data callable is only called if the cache needs to regenerate (when it has been * invalidated or empty, or the view file changed). * * If the callable $data returns NULL, then this will return NULL, too, without entering * the actual rendering process. * * You should use this method in your plugins instead of writing your own cache mechanism, * because this method handles PageResponse merging. Means: If templates used in this * $view are changing somehow the PageResponse ({{loadAsset('style.css')}} calls) then * this information (diff to current PageResponse) is stored and restored when we found * a html cache. The diff is beside the actual rendered HTML also stored in the cache * to keep this possible. * * @param string $cacheKey * @param string $view * @param array|callable $data Pass the data as array or a data provider function. * @param integer $lifeTime In seconds. Default is one hour/3600 seconds. * @param bool $force Force to bypass the cache and always call $data. For debuggin purposes. * * @see method `render` to get more information. * * @return string */ public function renderFullCached($cacheKey, $view, $data = null, $lifeTime = null, $force = false) { $cache = $this->cacher->getDistributedCache($cacheKey); $mTime = $this->getViewMTime($view); if (!is_string($cache)) { $cache = null; } else { $cache = @unserialize($cache); } if ($force || !$cache || !$cache['content'] || !is_array($cache) || $mTime != $cache['fileMTime']) { $oldResponse = clone $this->pageStack->getPageResponse(); $data2 = $data; if (is_callable($data)) { $data2 = call_user_func($data, $view); if (null === $data2) { //the data callback returned NULL so this means //we aren't the correct controller for this request //or the request contains invalid input return null; } } $content = $this->templating->render($view, $data2); $response = $this->pageStack->getPageResponse(); $diff = $oldResponse->diff($response); $cache = array('content' => $content, 'fileMTime' => $mTime, 'responseDiff' => $diff); $this->cacher->setDistributedCache($cacheKey, serialize($cache), $lifeTime ?: 3600); } else { if ($cache['responseDiff']) { $this->pageStack->getPageResponse()->patch($cache['responseDiff']); } } return $this->pageResponseFactory->createPluginResponse($cache['content']); }
public function fixResponse(GetResponseForControllerResultEvent $event) { $data = $event->getControllerResult(); if ($data instanceof PluginResponseInterface) { $response = $data; } else { $response = $this->pageResponseFactory->createPluginResponse($data); } $event->setResponse($response); }
public function onKernelView(GetResponseForControllerResultEvent $event) { $data = $event->getControllerResult(); $request = $event->getRequest(); if (!$event->getRequest()->attributes->get('_jarves_is_plugin')) { //we accept only plugin responses. return; } $content = $request->attributes->get('_content'); if (null !== $data) { if ($data instanceof PluginResponseInterface) { $response = $data; } else { $response = $this->pageResponseFactory->createPluginResponse($data); } //it's required to place a PluginResponseInterface as response, so //PluginResponseListener::onKernelResponse can correctly identify it //and set it as response for this plugin content, so ContentTypes\TypePlugin //can place the correct response at the correct position, without executing //the plugin twice. $event->setResponse($response); } else { //we hit a plugin route, but it has responsed with NULL //this means it is not responsible for this route/slug. //we need now to remove this plugin route from the route collection //and fire again a sub request until all plugins on this page //are handled. If no plugin is responsible for this url pattern //and the main page route is also not responsible //no response is set in the $event and a 404 is thrown by the HttpKernel. $foundRoute = false; $routes = $this->frontendRouteListener->getRoutes(); foreach ($routes as $idx => $route) { /** @var \Symfony\Component\Routing\Route $route */ if ($content === $route->getDefault('_content')) { //remove exactly only the current plugin that was hit in this sub request $routes->remove($idx); $foundRoute = true; break; } } if ($foundRoute) { //we've removed the route and fire now again a sub request $request = clone $this->pageStack->getRequest(); $request->attributes = new ParameterBag(); $response = $this->kernel->handle($request, HttpKernelInterface::SUB_REQUEST); $event->setResponse($response); } //we do not need to restore routes in the frontendRouteListener, because //it reload all routes on every master request } }
public function showAction() { return $this->pageResponseFactory->createFromRoute(); }
public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { //we need to reset all routes. They will anyway replaced by FrontendRouter::loadRoutes, //but to prevent caching conflicts, when a user removes a plugin for example //from a page, we need to know that without using actual caching. $this->routes = new RouteCollection(); $this->urlMatcher->__construct($this->routes, $this->requestContext); //prepare for new master request: clear the PageResponse object $this->pageStack->setCurrentPage(null); $this->pageStack->setCurrentDomain(null); $this->pageStack->setPageResponse($this->pageResponseFactory->create()); $this->frontendRouter->setRequest($request); $editorNodeId = (int) $this->pageStack->getRequest()->get('_jarves_editor_node'); $editorDomainId = (int) $this->pageStack->getRequest()->get('_jarves_editor_domain'); $domain = null; if ($editorDomainId) { $domain = $this->pageStack->getDomain($editorDomainId); if (!$domain) { //we haven't found any domain that is responsible for this request return; } $this->pageStack->setCurrentDomain($domain); } if ($editorNodeId) { //handle jarves content editor stuff //access is later checked if (!$editorNodeId && $domain) { $editorNodeId = $domain->getStartnodeId(); } $page = $this->pageStack->getPage($editorNodeId); if (!$page || !$page->isRenderable()) { //we haven't found any page that is responsible for this request return; } if (!$domain) { $domain = $this->pageStack->getDomain($page->getDomainId()); } $this->pageStack->setCurrentPage($page); $this->pageStack->setCurrentDomain($domain); $request->attributes->set('_controller', 'jarves.page_controller:handleAction'); } else { //regular frontend route search //search domain if (!$domain) { $domain = $this->frontendRouter->searchDomain(); if (!$domain) { //we haven't found any domain that is responsible for this request return; } $this->pageStack->setCurrentDomain($domain); } //search page $page = $this->frontendRouter->searchPage(); if (!$page || !$page->isRenderable()) { //we haven't found any page that is responsible for this request return; } $this->pageStack->setCurrentPage($page); if ($response = $this->frontendRouter->loadRoutes($this->routes, $page)) { //loadRoutes return in case of redirects and permissions a redirect or 404 response. $event->setResponse($response); return; } try { //check routes in $this->route parent::onKernelRequest($event); } catch (MethodNotAllowedException $e) { } catch (NotFoundHttpException $e) { } } } }