| @copyright 2007-2026 (c) AVE.cms
| @link https://ave-cms.ru
| @version 3.3
*/
namespace App\Frontend;
defined('BASEPATH') || die('Direct access to this location is not allowed.');
use App\Helpers\Debug;
use App\Helpers\Request;
use App\Common\AdminLocation;
use App\Frontend\Debug\PublicLayoutInspector;
/** Builds the public page from a resolved document and registered renderers. */
class PublicPageRenderer
{
/** @var object|null Kept for stored rubric PHP compatibility. */
public $curentdoc = null;
public $_doc_not_found = '
HTTP Error 404: Page not found
';
public $_rubric_template_empty = 'Ошибка
Не задан шаблон рубрики.';
public $_doc_not_published = 'Запрашиваемый документ запрещен к публикации.';
public $_doc_outside_publication_window = 'Документ недоступен посетителям: срок публикации ещё не наступил или уже завершён.';
public function resolveTemplate($template = null, $fetched = null, $templateId = null)
{
$resolver = new PageTemplateResolver();
$result = $resolver->resolve($this->curentdoc, array(
'only_content' => defined('ONLYCONTENT'),
'pop' => isset($_REQUEST['pop']) && $_REQUEST['pop'] == 1,
'fetched' => $fetched,
'template' => $template,
'template_id' => $templateId,
));
if (!empty($result['used_document_template'])) {
unset($this->curentdoc->template_text);
}
if (!defined('THEME_FOLDER')) {
define('THEME_FOLDER', $result['theme']);
}
return $result['text'];
}
public function resolveRubricPermissions($rubricId)
{
unset($_SESSION[$rubricId . '_docread']);
$resolver = new RubricPermissionResolver();
$embedded = isset($this->curentdoc->rubric_permission)
? $this->curentdoc->rubric_permission
: null;
$permissions = $resolver->resolve($rubricId, UGROUP, $embedded);
foreach ($permissions as $permission) {
$_SESSION[$rubricId . '_' . $permission] = 1;
}
return $permissions;
}
public function respondNotFound()
{
$responder = new PublicNotFoundResponder();
$responder->redirectToDocument(PAGE_NOT_FOUND_ID, $this->_doc_not_found);
}
public function documentIsAvailable()
{
$policy = new DocumentAccessPolicy();
$status = $policy->status($this->curentdoc, PAGE_NOT_FOUND_ID);
if ($status === DocumentAccessPolicy::AVAILABLE) {
return true;
}
if (in_array($status, array(DocumentAccessPolicy::DELETED, DocumentAccessPolicy::DELAYED), true)
&& (isset($_SESSION['adminpanel']) || isset($_SESSION['alles']))) {
$message = $status === DocumentAccessPolicy::DELAYED
? $this->_doc_outside_publication_window
: $this->_doc_not_published;
echo PublicNotice::render($message);
return true;
}
$this->curentdoc = false;
return false;
}
public function render($id, $rubricId = '')
{
Debug::startTime('DOC_' . $id);
\App\Common\ModuleTagRegistry::deferPrivate(true);
$cacheCompile = false;
$isAjax = Request::isAjax();
$renderCache = new DocumentRenderCache();
$documentFieldRepository = new DocumentFieldRepository();
$isRevisionPreview = DocumentFieldRepository::hasRevision((int) $id);
$componentRenderer = new PageComponentRenderer();
$shellRenderer = new PageShellRenderer();
$out = '';
// Определяем рубрику
define('RUB_ID', !empty($rubricId)
? $rubricId
: $this->curentdoc->rubric_id);
$main_content = '';
if (! \App\Frontend\PublicPageContext::hasDeferredPage() && (defined('CACHE_DOC_FULL') && CACHE_DOC_FULL)
&& !$isAjax && !PublicLayoutInspector::enabled())
{
if ($out = $renderCache->readPage(
$this->curentdoc, UGROUP, RUB_ID, $_REQUEST, $isAjax, PaginationRenderer::currentPage()
))
{
$this->resolveRubricPermissions(RUB_ID);
// Выполняем Код рубрики До загрузки документа
\App\Common\StoredPhpRuntime::evaluate(
' ?>' . $this->curentdoc->rubric_start_code . 'dispatch(
isset($_REQUEST['sysblock']) ? $_REQUEST['sysblock'] : null,
isset($_REQUEST['request']) ? $_REQUEST['request'] : null,
$isAjax,
PAGE_NOT_FOUND_ID,
$this->_doc_not_found
);
if ($externalContent['handled'])
{
$out = $externalContent['content'];
}
// В противном случае начинаем вывод документа
else
{
// проверяем параметры публикации документа
if (!$this->documentIsAvailable())
$this->respondNotFound();
\App\Frontend\PublicPageContext::setDocument($this->curentdoc);
$rubricPermissions = $this->resolveRubricPermissions(RUB_ID);
// Выполняем Код рубрики До загрузки документа
\App\Common\StoredPhpRuntime::evaluate(
' ?>' . $this->curentdoc->rubric_start_code . ' 0) {
$runtimeTemplate = (new \App\Frontend\PageTemplateRepository())->findText($runtimeTemplateId);
$out = $this->resolveTemplate(null, $runtimeTemplate, $runtimeTemplateId);
} else {
$out = $this->resolveTemplate(null, null, $this->curentdoc->rubric_template_id);
}
$rubricAccess = new \App\Frontend\RubricPermissionResolver();
if (! $rubricAccess->allows($rubricPermissions, 'docread'))
{ // читать запрещено - извлекаем ругательство и отдаём вместо контента
$main_content = PublicSettings::get('message_forbidden');
}
else
{
if ($isRevisionPreview)
{
// Preview не влияет на статистику документа.
}
elseif (isset ($_REQUEST['print']) && $_REQUEST['print'] == 1)
{
$viewTracker = new \App\Frontend\DocumentViewTracker();
$viewTracker->trackPrint($id);
}
elseif (\App\Frontend\PublicPageContext::hasDeferredPage())
{
$runtimePage = \App\Frontend\PublicPageContext::deferredPage();
$main_content = (string) $runtimePage['html'];
}
elseif (!$isRevisionPreview)
{
$viewTracker = new \App\Frontend\DocumentViewTracker();
$viewTracker->trackView($id);
}
// Runtime-страница использует документ только как оболочку сайта.
// Ее содержимое нельзя заменять кэшем или шаблоном рубрики.
if (! \App\Frontend\PublicPageContext::hasDeferredPage())
{
// Извлекаем скомпилированный шаблон документа из кэша
if (!$isRevisionPreview && defined('CACHE_DOC_TPL') && CACHE_DOC_TPL) // && empty ($_POST)
{
$documentFieldRepository->all((int) $this->curentdoc->Id);
$main_content = $renderCache->readTemplate($this->curentdoc, UGROUP, RUB_ID);
}
else
// Кэширование запрещено
$main_content = false;
// Собираем контент
// Если в кеше нет контента, то
if (empty($main_content))
{
// Основной/дополнительный шаблон уже разрешён DocumentRepository.
$rubTmpl = isset($this->curentdoc->rubric_template)
? (string) $this->curentdoc->rubric_template
: '';
$rubTmpl = trim($rubTmpl);
// Собираем шаблон рубрики
if (empty($rubTmpl))
{
// Если не задан шаблон рубрики, выводим сообщение
$main_content = $this->_rubric_template_empty;
}
else
{
// Обрабатываем основные поля рубрики
$renderer = new \App\Frontend\RubricTemplateRenderer();
$main_content = $renderer->render($rubTmpl, $this->curentdoc);
}
if (!$isRevisionPreview) {
$renderCache->writeTemplate($this->curentdoc, UGROUP, RUB_ID, $main_content);
}
}
}
}
$inspectedMainContent = PublicLayoutInspector::annotate($main_content, 'document', array(
'id' => isset($this->curentdoc->Id) ? (int) $this->curentdoc->Id : $id,
'title' => isset($this->curentdoc->document_title) ? (string) $this->curentdoc->document_title : 'Документ #' . $id,
'alias' => isset($this->curentdoc->document_alias) ? (string) $this->curentdoc->document_alias : '',
'tag' => '[tag:maincontent]',
'edit_url' => AdminLocation::url('documents/' . (int) $id . '/edit'),
));
$out = str_replace('[tag:maincontent]', $inspectedMainContent, $out);
unset ($this->curentdoc->rubric_template, $this->curentdoc->template);
}
//-- Конец вывода документа
// Тут мы вводим в хеадер и футер иньекцию скриптов.
if (defined('RUB_ID'))
{
$rubricHeader = isset($this->curentdoc->rubric_header_template)
? (string) $this->curentdoc->rubric_header_template
: '';
$rubricOpenGraph = isset($this->curentdoc->rubric_og_template)
? trim((string) $this->curentdoc->rubric_og_template)
: '';
if ($rubricOpenGraph !== '') {
$rubricHeader = rtrim($rubricHeader) . "\n" . $rubricOpenGraph;
}
$replace = [
'[tag:rubheader]' => $rubricHeader,
'[tag:rubfooter]' => $this->curentdoc->rubric_footer_template
];
$out = str_replace(array_keys($replace), array_values($replace), $out);
unset ($replace);
}
$themeMainContent = isset($inspectedMainContent) ? $inspectedMainContent : $main_content;
$out = (new ThemePageShellRenderer())->render($out, $themeMainContent, $this->curentdoc);
$out = $componentRenderer->render($out, $id, $this, $this->curentdoc);
$out = $shellRenderer->render($out, $main_content, $this->curentdoc);
unset($main_content);
PublicProfiler::record(array('DOCUMENT', 'FETCH'), Debug::endTime('DOC_' . $id));
if ($cacheCompile == false && !PublicLayoutInspector::enabled())
{
$renderCache->writePage(
$this->curentdoc, UGROUP, RUB_ID, $_REQUEST, $isAjax, PaginationRenderer::currentPage(), $out
);
}
}
\App\Common\ModuleTagRegistry::deferPrivate(false);
$out = (new ModuleTagRenderer())->renderPrivate($out, $this, $this->curentdoc);
// Выводим собранный документ
echo $out;
}
}
?>