<?php 
 
/* 
 * This file is part of Sulu. 
 * 
 * (c) Sulu GmbH 
 * 
 * This source file is subject to the MIT license that is bundled 
 * with this source code in the file LICENSE. 
 */ 
 
namespace Sulu\Bundle\WebsiteBundle\Controller; 
 
use Sulu\Bundle\HttpCacheBundle\CacheLifetime\CacheLifetimeEnhancerInterface; 
use Sulu\Bundle\PreviewBundle\Preview\Preview; 
use Sulu\Bundle\WebsiteBundle\Resolver\ParameterResolverInterface; 
use Sulu\Component\Content\Compat\StructureInterface; 
use Sulu\Component\Webspace\Analyzer\RequestAnalyzerInterface; 
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\HttpKernel\Exception\HttpException; 
 
/** 
 * Basic class to render Website from phpcr content. 
 */ 
abstract class WebsiteController extends AbstractController 
{ 
    /** 
     * Returns a rendered structure. 
     * 
     * @param StructureInterface $structure The structure, which has been loaded for rendering 
     * @param array $attributes Additional attributes, which will be passed to twig 
     * @param bool $preview Defines if the site is rendered in preview mode 
     * @param bool $partial Defines if only the content block of the template should be rendered 
     * 
     * @return Response 
     */ 
    protected function renderStructure( 
        StructureInterface $structure, 
        $attributes = [], 
        $preview = false, 
        $partial = false 
    ) { 
        /** @var Request $request */ 
        $request = $this->getRequest(); 
 
        // extract format twig file 
        if (!$preview) { 
            $requestFormat = $request->getRequestFormat(); 
        } else { 
            $requestFormat = 'html'; 
        } 
 
        $viewTemplate = $structure->getView() . '.' . $requestFormat . '.twig'; 
 
        if (!$this->get('twig')->getLoader()->exists($viewTemplate)) { 
            throw new HttpException( 
                406, 
                \sprintf('Page does not exist in "%s" format.', $requestFormat) 
            ); 
        } 
 
        // get attributes to render template 
        $data = $this->getAttributes($attributes, $structure, $preview); 
 
        // if partial render only content block else full page 
        if ($partial) { 
            $content = $this->renderBlock( 
                $viewTemplate, 
                'content', 
                $data 
            ); 
        } elseif ($preview) { 
            $content = $this->renderPreview( 
                $viewTemplate, 
                $data 
            ); 
        } else { 
            $content = $this->renderView( 
                $viewTemplate, 
                $data 
            ); 
        } 
 
        $response = new Response($content); 
 
        // we need to set the content type ourselves here 
        // else symfony will use the accept header of the client and the page could be cached with false content-type 
        // see following symfony issue: https://github.com/symfony/symfony/issues/35694 
        $mimeType = $request->getMimeType($requestFormat); 
 
        if ($mimeType) { 
            $response->headers->set('Content-Type', $mimeType); 
        } 
 
        if (!$preview && $this->getCacheTimeLifeEnhancer()) { 
            $this->getCacheTimeLifeEnhancer()->enhance($response, $structure); 
        } 
 
        return $response; 
    } 
 
    /** 
     * Generates attributes. 
     * 
     * @param mixed[] $attributes 
     * @param bool $preview 
     * 
     * @return mixed[] 
     */ 
    protected function getAttributes($attributes, ?StructureInterface $structure = null, $preview = false) 
    { 
        return $this->get('sulu_website.resolver.parameter')->resolve( 
            $attributes, 
            $this->get('sulu_core.webspace.request_analyzer'), 
            $structure, 
            $preview 
        ); 
    } 
 
    /** 
     * Returns rendered part of template specified by block. 
     */ 
    protected function renderBlock($template, $block, $attributes = []) 
    { 
        $twig = $this->get('twig'); 
        $attributes = $twig->mergeGlobals($attributes); 
 
        $template = $twig->load($template); 
 
        $level = \ob_get_level(); 
        \ob_start(); 
 
        try { 
            $rendered = $template->renderBlock($block, $attributes); 
            \ob_end_clean(); 
 
            return $rendered; 
        } catch (\Exception $e) { 
            while (\ob_get_level() > $level) { 
                \ob_end_clean(); 
            } 
 
            throw $e; 
        } 
    } 
 
    protected function renderPreview(string $view, array $parameters = []): string 
    { 
        $parameters['previewParentTemplate'] = $view; 
        $parameters['previewContentReplacer'] = Preview::CONTENT_REPLACER; 
 
        return parent::renderView('@SuluWebsite/Preview/preview.html.twig', $parameters); 
    } 
 
    /** 
     * Returns the current request from the request stack. 
     * 
     * @return Request 
     * 
     * @deprecated will be remove with 2.0 
     */ 
    public function getRequest() 
    { 
        return $this->get('request_stack')->getCurrentRequest(); 
    } 
 
    protected function getCacheTimeLifeEnhancer(): ?CacheLifetimeEnhancerInterface 
    { 
        if (!$this->has('sulu_http_cache.cache_lifetime.enhancer')) { 
            return null; 
        } 
 
        /** @var CacheLifetimeEnhancerInterface $cacheLifetimeEnhancer */ 
        $cacheLifetimeEnhancer = $this->get('sulu_http_cache.cache_lifetime.enhancer'); 
 
        return $cacheLifetimeEnhancer; 
    } 
 
    public static function getSubscribedServices() 
    { 
        $subscribedServices = parent::getSubscribedServices(); 
        $subscribedServices['sulu_website.resolver.parameter'] = ParameterResolverInterface::class; 
        $subscribedServices['sulu_core.webspace.request_analyzer'] = RequestAnalyzerInterface::class; 
        $subscribedServices['sulu_http_cache.cache_lifetime.enhancer'] = '?' . CacheLifetimeEnhancerInterface::class; 
 
        return $subscribedServices; 
    } 
}