<?php /** * This file is part of Jarves. * * (c) Marc J. Schmidt <marc@marcjschmidt.de> * * J.A.R.V.E.S - Just A Rather Very Easy [content management] System. * * http://jarves.io * * To get the full copyright and license information, please view the * LICENSE file, that was distributed with this source code. */ namespace Jarves; use Jarves\Cache\Cacher; use Jarves\ContentTypes\AbstractType; use Jarves\ContentTypes\ContentRendererAwareContentType; use Jarves\Model\Base\ContentQuery; use Jarves\Model\Content; use Jarves\ContentTypes\TypeNotFoundException; use Jarves\Model\ContentInterface; use Propel\Runtime\Map\TableMap; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\GenericEvent; use Symfony\Component\Templating\EngineInterface; class ContentRender { /** * Cache of the current contents stage. * * @var array */ public $contents; /** * @var Jarves */ private $jarves; /** * @var StopwatchHelper */ private $stopwatch; /** * @var EditMode */ private $editMode; /** * @var Cacher */ private $cacher; /** * @var EventDispatcherInterface */ private $eventDispatcher; /** * @var PageStack */ private $pageStack; /** * @var AbstractType[] */ protected $types = []; /** * @var EngineInterface */ private $templating; /** * @param Jarves $jarves * @param StopwatchHelper $stopwatch * @param EditMode $editMode * @param Cacher $cacher * @param EventDispatcherInterface $eventDispatcher * @param PageStack $pageStack * @param EngineInterface $templating */ function __construct(Jarves $jarves, StopwatchHelper $stopwatch, EditMode $editMode, Cacher $cacher, EventDispatcherInterface $eventDispatcher, PageStack $pageStack, EngineInterface $templating) { $this->jarves = $jarves; $this->stopwatch = $stopwatch; $this->editMode = $editMode; $this->cacher = $cacher; $this->eventDispatcher = $eventDispatcher; $this->pageStack = $pageStack; $this->templating = $templating; } /** * @param string $type * @param AbstractType $contentType */ public function addType($type, $contentType) { $this->types[$type] = $contentType; if ($contentType instanceof ContentRendererAwareContentType) { $contentType->setContentRenderer($this); } } /** * @param string $type * * @return AbstractType */ public function getTypeRenderer($type) { return isset($this->types[$type]) ? $this->types[$type] : $this->types[strtolower($type)]; } /** * @return ContentTypes\AbstractType[] */ public function getContentTypes() { return $this->types; } /** * @param integer $nodeId * @param integer $slotId * @param array $params * * @return string */ public function renderSlot($nodeId = null, $slotId = 1, $params = array()) { $params['id'] = $slotId; $disableEditor = isset($params['_disable_editor']) && $params['_disable_editor'] ? true : false; if ($this->editMode->isEditMode() && !$disableEditor) { return '<div class="jarves-slot" params="' . htmlspecialchars(json_encode($params)) . '"></div>'; } if (!$nodeId) { $nodeId = $this->pageStack->getCurrentPage()->getId(); } $contents = $this->getSlotContents($nodeId, $slotId); return $this->renderContents($contents, $params); } /** * @param integer $nodeId * @param integer $slotId * @param array $params * * @return string */ public function renderSingleSlot($nodeId = null, $slotId = 1, $params = array()) { $params['id'] = $slotId; $disableEditor = isset($params['_disable_editor']) && $params['_disable_editor'] ? true : false; if ($this->editMode->isEditMode() && !$disableEditor) { return '<div class="jarves-slot jarves-single-slot" params="' . htmlspecialchars(json_encode($params)) . '"></div>'; } if (!$nodeId) { $nodeId = $this->pageStack->getCurrentPage()->getId(); } $contents = $this->getSlotContents($nodeId, $slotId); return $this->renderContents($contents, $params); } /** * @param integer $nodeId * @param integer $slotId * @return Model\Content[] */ public function getSlotContents($nodeId, $slotId) { if ($contents = $this->pageStack->getPageResponse()->getPageContent()) { if (is_array($contents) && $contents[$slotId]) { return $contents[$slotId]; } else if (is_string($contents)) { return $contents; } } $cacheKey = 'core/contents/' . $nodeId . '.' . $slotId; $cache = $this->cacher->getDistributedCache($cacheKey); $contents = null; if ($cache) { return unserialize($cache); } $contents = ContentQuery::create() ->filterByNodeId($nodeId) ->filterByBoxId($slotId) ->orderByRank() ->find(); $this->cacher->setDistributedCache($cacheKey, serialize($contents)); return $contents; } // // public function renderView(&$contents, $view) // { // return json_encode(iterator_to_array($contents)); // } /** * Build HTML for given contents. * * @param array $contents * @param array $slotProperties * * @return string|null */ public function renderContents(&$contents, $slotProperties) { $name = isset($slotProperties['name']) ? $slotProperties['name'] : ''; $title = sprintf('Slot %s [%d]', $name, $slotProperties['id']); $this->stopwatch->start($title, 'Jarves'); if (is_string($contents)) { return $contents; } $filteredContents = array(); if (!($contents instanceof \Traversable)) { return; } /** @var $content Content */ foreach ($contents as $content) { $access = true; if (is_string($content)) { $filteredContents[] = $content; continue; } if ( ($content->getAccessFrom() + 0 > 0 && $content->getAccessFrom() > time()) || ($content->getAccessTo() + 0 > 0 && $content->getAccessTo() < time()) ) { $access = false; } if ($content->getHide()) { $access = false; } if ($access && $content->getAccessFromGroups()) { $access = false; $groups = ',' . $content->getAccessFromGroups() . ','; $userGroups = $this->pageStack->getUser()->getUserGroups(); foreach ($userGroups as $group) { if (strpos($groups, ',' . $group->getGroupId() . ',') !== false) { $access = true; break; } } if (!$access) { $adminGroups = $this->pageStack->getUser()->getUserGroups(); foreach ($adminGroups as $group) { if (strpos($groups, ',' . $group->getGroupId() . ',') !== false) { $access = true; break; } } } } if ($access) { $filteredContents[] = $content; } } $count = count($filteredContents); /* * Compatibility */ $data['layoutContentsMax'] = $count; $data['layoutContentsIsFirst'] = true; $data['layoutContentsIsLast'] = false; $data['layoutContentsId'] = @$slotProperties['id']; $data['layoutContentsName'] = @$slotProperties['name']; $i = 0; //$oldContent = $tpl->getTemplateVars('content'); $this->eventDispatcher->dispatch('core/render/slot/pre', new GenericEvent($data)); $html = ''; if ($count > 0) { foreach ($filteredContents as $content) { if (is_string($content)) { $html .= $content; continue; } if ('stopper' === $content->getType()) { if ($html) { break; } continue; } if ($i == $count) { $data['layoutContentsIsLast'] = true; } if ($i > 0) { $data['layoutContentsIsFirst'] = false; } $i++; $data['layoutContentsIndex'] = $i; $html .= $this->renderContent($content, $data); } } $argument = array($data, &$html); $this->eventDispatcher->dispatch('core/render/slot', new GenericEvent($argument)); $this->stopwatch->stop($title); return $html; } /** * Build HTML for given content. * * @param ContentInterface $content * @param array $parameters * @return string * @throws TypeNotFoundException */ public function renderContent(ContentInterface $content, $parameters = array()) { $type = $content->getType() ?: 'text'; if ('stopper' === $type) { return ''; } $title = sprintf('Content %d [%s]', $content->getId(), $type); $this->stopwatch->start($title, 'Jarves'); $typeRenderer = $this->getTypeRenderer($type); if (!$typeRenderer) { $this->stopwatch->stop($title); throw new TypeNotFoundException(sprintf( 'Type renderer for `%s` not found. [%s] %s', $type, json_encode($content), json_encode(array_keys($this->types)) )); } $typeRenderer->setContent($content); $typeRenderer->setParameters($parameters); $html = $typeRenderer->render(); $data['content'] = $content->toArray(TableMap::TYPE_CAMELNAME); $data['parameter'] = $parameters; $data['html'] = $html; $this->eventDispatcher->dispatch('core/render/content/pre', new GenericEvent($data)); $unsearchable = false; if ((!is_array($content->getAccessFromGroups()) && $content->getAccessFromGroups() != '') || (is_array($content->getAccessFromGroups()) && count($content->getAccessFromGroups()) > 0) || ($content->getAccessFrom() > 0 && $content->getAccessFrom() > time()) || ($content->getAccessTo() > 0 && $content->getAccessTo() < time()) || $content->getUnsearchable() ) { $unsearchable = true; } if ($html) { if ($content->getTemplate() == '' || $content->getTemplate() == '-') { if ($unsearchable && $data['html']) { $result = '<!--unsearchable-begin-->' . $data['html'] . '<!--unsearchable-end-->'; } else { $result = $data['html']; } } else { $result = $this->templating->render($content->getTemplate(), $data); if ($unsearchable && $result) { $result = '<!--unsearchable-begin-->' . $result . '<!--unsearchable-end-->'; } } } $argument = array(&$result, $data); $this->eventDispatcher->dispatch('core/render/content', new GenericEvent($argument)); $this->stopwatch->stop($title); return $result; } }