*/'; protected $_layoutTemplate; protected $_smarty; protected $_smartyPluginPaths = [ 'lib/Smarty/Smarty/plugins', 'lib/Smarty/app_plugins', ]; protected $_content = [ 'htmlAttribs' => [ 'xmlns' => 'http://www.w3.org/1999/xhtml', 'class' => 'no-js', 'lang' => 'en-us', ], 'head' => [ 'keywords' => '', 'description' => '', 'meta' => [], 'base' => '', 'stylesheet' => [], 'script' => [], 'inlineScript' => [], 'readyFunctions' => [], 'initFunctions' => [], ], 'bodyAttribs' => ['onload' => 'bodyOnLoad()'], 'bodyTemplate' => null, 'menu' => null, 'ctrlMenu' => null, 'ITEMS' => [], ]; protected $_widgets = []; protected $_titleFormat = '[{title}][{separator}Page {pageNumber}][{titleSuffix}]'; protected $_titleSeparator = ' :: '; protected $_titleParts = []; protected $_pageNumber; protected $_siteName; protected $_titleSuffix; protected $_resourcesIgnoredAttribs = [ 'skipPacking', // якщо стилю чи скрипту в атрибутах передати 'skipPacking' => true, то Qs_Packer такі ресурси мерджити не буде ]; protected $_defaultGroupName = 'ITEMS'; protected $_groupName; protected $_smartyPlugins = [ 'block' => [], ]; protected $_templateRootPath; protected $_outFilters = []; protected $_templateDefines = [ 'BASE_URL', 'BASE_URL_LANGUAGE', 'CURRENT_PAGE', 'CURRENT_PAGE_FINAL', 'PARENT_PAGE', 'PARENT_PAGE_FINAL', 'BASE_PATH', 'CURRENT_LANGUAGE', 'SITE_LIVE', 'DEFAULT_LANGUAGE', 'NOINDEX_BEGIN', 'NOINDEX_END', 'SITE_REVISION', ]; protected $_scriptDefines = [ 'BASE_URL', 'BASE_URL_LANGUAGE', 'CURRENT_PAGE', 'CURRENT_PAGE_FINAL', 'SITE_LIVE', 'PARENT_PAGE', 'PARENT_PAGE_FINAL', 'CURRENT_LANGUAGE', 'DEFAULT_LANGUAGE', 'DEBUG', 'SITE_REVISION', 'OPTIMIZE_RESOURCES', 'USE_PACKED_RESOURCES', 'IS_MOBILE', ]; protected $_view; protected $_authClassName; protected $_authAdapterClassName; /** * @var Qs_Auth */ protected $_auth; /** * @var Qs_Auth_Adapter_DbTable */ protected $_authAdapter; protected $_hasAuthentication = false; protected $_options = []; protected $_optimized = false; protected $_hasAnalyticsScripts = false; /** * Module specific Placeholders e.g.: [ * 'User\\' => [ * 'firstName' => 'John', * ] * ] * @var array */ protected $_modulePlaceholders = []; /** * @var Qs_Lock_RoleObj */ protected $_lockObj; /** @var array */ protected $_gtmValues = []; protected $_isPagePreviewMode = false; public function __construct($options = []) { $this->setBase(Qs_Constant::get('BASE_URL') . '/'); $this->setOptions($options); Qs_Options::setConstructorOptions($this); $this->_init(); } protected function _init() { /** @var $viewRenderer Zend_Controller_Action_Helper_ViewRenderer */ $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); if (null == $viewRenderer->view) { $viewRenderer->setView(Qs_View::getInstance()); } $this->_initMessages(); if (!$this->isPagePreviewMode() && $this->_hasAuthentication) { $this->authenticate(); } return $this; } protected function _initMessages() { if (Qs_Request::isXmlHttpRequest()) { // Don't remove messages in Ajax requests return $this; } $session = new Qs_Session_Namespace(Qs_Constant::get('CURRENT_PAGE')); if (isset($session->message)) { $this->displayMessage($session->message); unset($session->message); } if (isset($session->error)) { $this->displayError($session->error); unset($session->error); } if (isset($session->attention)) { $this->displayAttention($session->attention); unset($session->attention); } return $this; } public function hasAnalyticsScripts() { return $this->_hasAnalyticsScripts; } public function setHasAnalyticsScripts($value = true) { $this->_hasAnalyticsScripts = (bool) $value; return $this; } public function setAnalyticsType($type) { if (!in_array($type, [self::ANALYTICS_TYPE_GOOGLE_ANALYTICS, self::ANALYTICS_TYPE_GOOGLE_TAG_MANAGER])) { throw new Qs_Exception('Undefined analytics type'); } $this->_analyticsType = $type; return $this; } public function getAnalyticsType() { if (null === $this->_analyticsType) { $map = [ 'gtmId' => self::ANALYTICS_TYPE_GOOGLE_TAG_MANAGER, 'analyticsCode' => self::ANALYTICS_TYPE_GOOGLE_ANALYTICS, ]; // use cached 'false' value for further method calls in case both codes are empty $this->_analyticsType = false; foreach ($map as $field => $type) { $code = App_Settings_Obj::get($field); $code = trim($code); if (!empty($code)) { $this->_analyticsType = $type; break; } } } return $this->_analyticsType; } public function isGtmEnabled() { return constant('SITE_LIVE') && $this->getAnalyticsType() == self::ANALYTICS_TYPE_GOOGLE_TAG_MANAGER && App_Settings_Obj::get('gtmId'); } public function addGtmValues(array $values) { $this->_gtmValues = Qs_Array::mergeRecursive($this->_gtmValues, $values); return $this; } public function setGtmValue($name, $value) { $this->_gtmValues[$name] = $value; return $this; } public function getGtmValues() { return $this->_gtmValues; } public function setAuthentication($value) { $this->_hasAuthentication = (bool) $value; return $this; } public function getAuthentication() { return (bool) $this->_hasAuthentication; } public function setOptions($options) { if (isset($options['options'])) { unset($options['options']); } foreach ($options as $key => $value) { $this->setOption($key, $value); } return $this; } public function getOptions() { return $this->_options; } public function setOption($name, $value) { $method = 'set' . ucfirst($name); if (method_exists($this, $method)) { $this->$method($value); } else { $this->_options[$name] = $value; } return $this; } public function getOption($name) { if (array_key_exists($name, $this->_options)) { return $this->_options[$name]; } return false; } public function setDescription($description) { $this->_content['head']['description'] = $description; return $this; } public function appendHeader($append) { $this->setHeader($this->getHeader() . $append); return $this; } public function setHeader($header) { $this->assign('header', $header); return $this; } public function getHeader() { return $this->getTemplateVariable('header'); } public function getTemplateVariables() { return $this->_content; } public function getTemplateVariable($name) { if (array_key_exists($name, $this->_content)) { return $this->_content[$name]; } return null; } public function setKeywords($keywords) { $this->_content['head']['keywords'] = $keywords; return $this; } public function getView() { if (null === $this->_view) { $this->_view = Qs_View::getInstance(); } return $this->_view; } public function clearStylesheets() { $this->_content['head']['stylesheet'] = []; return $this; } public function clearInlineScripts() { $this->_content['head']['inlineScript'] = []; return $this; } public function clearInitFunctions() { $this->_content['head']['initFunctions'] = []; return $this; } public function clearScripts() { $this->_content['head']['script'] = []; return $this; } public function setStylesheets(array $list) { $this->clearStylesheets(); $this->addStylesheets($list); return $this; } public function addStylesheets(array $list) { foreach ($list as $options) { if (is_array($options)) { call_user_func_array([$this, 'addStylesheet'], $options); } else { $this->addStylesheet($options); } } return $this; } public function addStylesheet($href, $_attribs = [], $name = null) { $attribs = [ 'href' => $href, 'media' => 'all', 'type' => 'text/css', 'rel' => 'stylesheet', ]; if (null === $name) { if (strncmp($href, 'css/', 4) == 0) { $name = substr($href, 4); $name = str_replace('.css', '', $name); } else { $name = $href; } } if (isset($this->_content['head']['stylesheet'][$name])) { return $this; } $this->_content['head']['stylesheet'][$name] = array_merge($attribs, $_attribs); return $this; } public function getStylesheetUrls() { return array_column($this->_content['head']['stylesheet'], 'href'); } public function setScripts(array $list) { $this->clearScripts(); $this->addScripts($list); return $this; } public function addScripts(array $list) { foreach ($list as $options) { if (is_array($options)) { call_user_func_array([$this, 'addScript'], $options); } else { $this->addScript($options); } } return $this; } public function addScript($src, $_attribs = [], $name = null) { $attribs = [ 'src' => $src, // Tag is not correctly works in IE8 'type' => 'text/javascript', //'language' => 'JavaScript', ]; if (null === $name) { if (strncmp($src, 'js/', 3) == 0) { $name = substr($src, 3, -3); } else { $name = $src; } } if (isset($this->_content['head']['script'][$name])) { return $this; } $script = array_merge($attribs, $_attribs); if ($src === 'js/jquery-ui.js' && array_key_exists('jquery', $this->_content['head']['script'])) { /** * Put jquery-ui.js after jquery.js to avoid conflicts with bootstrap * https://stackoverflow.com/questions/17458224/ */ Qs_Array::mergeAssocAfter($this->_content['head']['script'], [$name => $script], 'jquery'); } else { $this->_content['head']['script'][$name] = $script; } return $this; } public function addInlineScript($name, $body, $_attribs = []) { $attribs = [ 'type' => 'text/javascript', 'beforeScripts' => false, ]; $attribs = array_merge($attribs, $_attribs); $beforeScripts = (int) $attribs['beforeScripts']; unset($attribs['beforeScripts']); $this->_content['head']['inlineScript'][$beforeScripts][$name] = [ 'attribs' => $attribs, 'body' => $body, ]; return $this; } protected function _getHeadPart($part) { if (array_key_exists($part, $this->_content['head'])) { return $this->_content['head'][$part]; } return null; } protected function _setHeadPart($part, $attribs) { $this->_content['head'][$part] = $attribs; return $this; } public function appendTitle($append) { $this->_titleParts[] = $append; return $this; } public function prependTitle($prepend) { array_unshift($this->_titleParts, $prepend); return $this; } public function setTitle($title) { $this->_titleParts = [$title]; return $this; } /** * @param string $titleFormat * @return $this */ public function setTitleFormat($titleFormat) { $this->_titleFormat = $titleFormat; return $this; } /** * @return string */ public function getTitleFormat() { return $this->_titleFormat; } /** * @param array $titleParts * @return $this */ public function setTitleParts($titleParts) { $this->_titleParts = $titleParts; return $this; } /** * @return array */ public function getTitleParts() { return $this->_titleParts; } /** * @param string $titleSeparator * @return $this */ public function setTitleSeparator($titleSeparator) { $this->_titleSeparator = $titleSeparator; return $this; } /** * @return string */ public function getTitleSeparator() { return $this->_titleSeparator; } /** * @param mixed $siteName * @return $this */ public function setSiteName($siteName) { $this->_siteName = $siteName; return $this; } /** * @return mixed */ public function getSiteName() { if (null === $this->_siteName) { $this->setSiteName(constant('SITE_NAME')); } return $this->_siteName; } /** * @param mixed $pageNumber * @return $this */ public function setPageNumber($pageNumber) { $this->_pageNumber = (int) $pageNumber; return $this; } /** * @return mixed */ public function getPageNumber() { return $this->_pageNumber; } public function getTitleSuffix() { if (null === $this->_titleSuffix) { $this->_titleSuffix = App_Settings_Obj::get('titleSuffix'); } return $this->_titleSuffix; } public function setTitleSuffix($titleSuffix) { $this->_titleSuffix = $titleSuffix; return $this; } public function getTitle() { return Qs_String::fill( $this->getTitleFormat(), [ 'title' => implode($this->getTitleSeparator(), $this->getTitleParts()), 'separator' => $this->getTitleSeparator(), 'pageNumber' => $this->getPageNumber() > 1 ? $this->getPageNumber() : null, 'titleSuffix' => $this->getTitleSuffix(), ] ); } public function setBase($base) { return $this->_setHeadPart('base', $base); } public function getTemplateDirectory() { if (null == $this->_templateRootPath) { $this->setTemplateRootPath(Qs_Constant::get('BASE_PATH') . '/tpl'); } return $this->_templateRootPath; } public function setTemplateRootPath($directory) { $this->_templateRootPath = strval($directory); if (is_object($this->_smarty)) { $this->_smarty->template_dir = $this->_templateRootPath; } return $this; } public function getLayoutTemplate() { if (null === $this->_layoutTemplate) { $this->setLayoutTemplate('index.tpl'); } return $this->_layoutTemplate; } public function setLayoutTemplate($_template) { if ('.' === dirname($_template)) { $template = $this->getTemplate($_template); } else { $template = $_template; } if (empty($template)) { $message = 'Invalid layout template "' . $_template . '" not found in paths: "' . implode('", "', $this->getTemplatePath()) . '".'; throw new Qs_Doc_Exception($message); } $this->_layoutTemplate = $template; return $this; } public function getBodyTemplate() { if (null === $this->_getHeadPart('bodyTemplate')) { $this->_setHeadPart('bodyTemplate', $this->getTemplate('Body/default.tpl')); } return $this->_getHeadPart('bodyTemplate'); } public function setBodyTemplate($_template) { if ('.' === dirname($_template)) { $template = $this->getTemplate('Body/' . $_template); } else { $template = $_template; } if (empty($template)) { Qs_Debug::log('Body template "' . $_template . '" not found in paths: "' . implode('", "', $this->getTemplatePath()) . '".'); if (false === ($template = $this->getTemplate('Body/default.tpl'))) { $message = 'Body template "' . $_template . '" not found in paths: "' . implode('", "', $this->getTemplatePath()) . '".'; throw new Qs_Doc_Exception($message); } } $this->_setHeadPart('bodyTemplate', $template); return $this; } /** * @param string $var * @param mixed $value * @return Qs_Doc */ public function assign($var, $value = false) { $this->_content[$var] = $value; return $this; } public function registerOutputFilter($filter) { $this->unregisterOutputFilter($filter); $this->_outFilters[] = $filter; return $this; } public function unregisterOutputFilter($filter) { $key = array_search($filter, $this->_outFilters); if (false !== $key) { unset($this->_outFilters[$key]); } return $this; } public function setOptimized($flag = true) { $this->_optimized = (bool) $flag; return $this; } public function getOptimized() { return $this->_optimized; } protected function _optimize() { if ($this->_optimized || !Qs_Constant::get('OPTIMIZE_RESOURCES')) { return $this; } if (false !== ($mergedStylesheets = Qs_Packer::getMergedStylesheets($this->_content['head']['stylesheet']))) { $this->setStylesheets($mergedStylesheets); } if (false !== ($mergedScripts = Qs_Packer::getMergedScripts($this->_content['head']['script']))) { $this->setScripts($mergedScripts); } $this->_optimized = true; return $this; } public function fetch($template = null) { $this->_optimize(); $this->getSmarty()->assign('AUTH_INFO', $this->getAuthIdentity()); $this->getSmarty()->assign('scriptDefines', $this->_scriptDefines); $this->addInlineScript( 'isMobile', 'qs.constant("IS_TOUCHSCREEN", ' . ((Qs_Device::isTouchscreen()) ? 'true' : 'false') . ');' ); if (Qs_Navigation::isEnabled() && false != ($nav = Qs_Navigation::get())) { $this->getSmarty()->assign('NAVIGATION', $nav); } foreach ($this->_resourcesIgnoredAttribs as $attribute) { foreach (['stylesheet', 'script'] as $resourceType) { foreach ($this->_content['head'][$resourceType] as &$resource) { if (array_key_exists($attribute, $resource)) { unset($resource[$attribute]); } } } } $html = $this->fetchTemplate($template); foreach ($this->_outFilters as $filter) { $html = call_user_func_array($filter, [$html, $this]); } return $html; } public function fetchTemplate($template = null) { $this->getSmarty()->assign('view', Qs_View::getInstance()); if (is_array($this->_templateDefines) && !empty($this->_templateDefines)) { foreach ($this->_templateDefines as $v) { $this->assign($v, Qs_Constant::get($v)); } } $this->getSmarty()->assign($this->getTemplateVariables()); $this->getSmarty()->assign('DOC', $this); $this->getSmarty()->assign('IS_TOUCHSCREEN', Qs_Device::isTouchscreen()); /** @var $debug Qs_Debug */ $debug = Zend_Registry::get('debug'); $debug->setErrorReporting($debug->getErrorReporting() ^ E_NOTICE); $html = $this->getSmarty()->fetch((null === $template) ? $this->getLayoutTemplate() : $template); $debug->restoreErrorReporting(); return $html; } public function fetchItem(array $item) { $this->getSmarty()->assign('item', new Qs_Doc_Item($item)); return $this->fetchTemplate($item['tpl']); } protected function _beforeDisplay() { $this->_initGtmValues(); $this->_initFooter(); return $this; } protected function _initGtmValues() { if ($this->isGtmEnabled()) { $values = (array) $this->_gtmValues; array_walk_recursive($values, function (&$item) { $item = (string) $item; }); $values = json_encode($values, JSON_PRETTY_PRINT); $this->assign('GTM_VALUES', $values); } return $this; } protected function _initFooter() { $data = (array) $this->_getFooterPlaceholders(); $this->assign('FOOTER', Qs_String::fill(App_Settings_Obj::get('footer'), $data)); return $this; } protected function _getFooterPlaceholders() { return [ 'currentYear' => date('Y'), 'widgets' => '', ]; } public function sendHeaders() { header('Content-Type: ' . Qs_Constant::get('CONTENT_TYPE')); return $this; } public function display404($options = []) { $notFound = new App_NotFound_View($options); $notFound->setDoc($this); $notFound->exec(); return $this; } public function display() { $this->_beforeDisplay(); $this->sendHeaders(); echo $this->fetch(); return $this; } public function __toString() { $this->_beforeDisplay(); return $this->fetch(); } protected function _displayMessageBox(array $messages, $type) { $template = $this->getTemplate($type . '.tpl'); foreach ($messages as $message) { $this->addItem(['tpl' => $template, 'message' => $message]); } return $this; } public function renderError($message) { return $this->fetchItem(['tpl' => $this->getTemplate('error.tpl'), 'message' => $message]); } public function renderMessage($message) { return $this->fetchItem(['tpl' => $this->getTemplate('message.tpl'), 'message' => $message]); } public function displayMessage($messages) { $messages = (array) $messages; $this->_displayMessageBox($messages, static::MESSAGE_BOX_MESSAGE); return $this; } public function displayError($errors) { $errors = (array) $errors; $this->_displayMessageBox($errors, static::MESSAGE_BOX_ERROR); return $this; } public function displayAttention($attentions) { $attentions = (array) $attentions; $this->_displayMessageBox($attentions, static::MESSAGE_BOX_ATTENTION); return $this; } public function hasAuth() { $file = BASE_PATH . '/' . str_replace(['_', '\\'], '/', $this->_authClassName) . '.php'; return (null !== $this->_auth || (null !== $this->_authClassName && file_exists($file))); } public function getAuth() { if (null === $this->_auth) { if (null === $this->_authClassName) { throw new Qs_Doc_Exception('Auth is undefined'); } else { $this->_auth = call_user_func($this->_authClassName . '::getInstance'); } } return $this->_auth; } public function setAuth($auth) { if (!($auth instanceof Qs_Auth)) { throw new Qs_Doc_Exception('Auth is not instance of Qs_Auth'); } $this->_auth = $auth; return $this; } public function getAuthAdapter() { if (null === $this->_authAdapter) { if (null === $this->_authAdapterClassName) { if (null == $this->_auth) { if (null === $this->_authClassName) { throw new Qs_Doc_Exception('AuthAdapter is undefined'); } $this->_authAdapterClassName = $this->_authClassName . 'Adapter'; } else { $this->_authAdapterClassName = get_class($this->_auth) . 'Adapter'; } } $this->_authAdapter = new $this->_authAdapterClassName(); } return $this->_authAdapter; } public function setAuthAdapter($authAdaptrer) { if (!($authAdaptrer instanceof Zend_Auth_Adapter_Interface)) { throw new Qs_Doc_Exception('AuthAdapter is not instance of Zend_Auth_Adapter_Interface'); } $this->_authAdapter = $authAdaptrer; return $this; } public function authenticate() { /** @var $result Zend_Auth_Result */ $result = null; if ($this->getAuth()->hasIdentity()) { $data = $this->getAuth()->getIdentity(); $this->getAuthAdapter()->setIdentity($data); $result = $this->getAuth()->authenticate($this->getAuthAdapter()); if ($result->isValid()) { return true; } else { $this->getAuth()->clearIdentity(); } } if (Qs_Request::isXmlHttpRequest()) { $this->_processAjaxFailedAuth(); } else { $this->getAuth()->setBackUrl(Qs_Request::getUrl()); if ($result) { $session = new Zend_Session_Namespace($this->getAuth()->getLoginAlias()); $session->{self::MESSAGE_BOX_ERROR} = $result->getMessages(); $session->setExpirationHops(1, self::MESSAGE_BOX_ERROR); } Qs_Http::redirect($this->getAuth()->getLoginUrl()); } return $this; } protected function _processAjaxFailedAuth() { $this->ajaxResponse([ 'isValid' => true, 'sessionExpired' => true, 'loginUrl' => $this->getAuth()->getLoginUrl() . '?' . Qs_Doc::POPUP, ]); return $this; } public function ajaxResponse($response = []) { header('Cache-Control: no-store, no-cache, must-revalidate, private'); header('Pragma: no-cache'); header('Content-Type: application/x-javascript; charset=utf-8'); die(json_encode($response)); } public function getAuthData($field = false, $default = null) { if ($this->hasAuth()) { return $this->getAuth()->getData($field, $default); } return $default; } public function getAuthIdentity() { if ($this->hasAuth()) { $identity = $this->getAuth()->getIdentity(); if (!empty($identity) && array_key_exists('autologinCode', $identity)) { if (count($identity) == 1) { // has only 'autologinCode' $this->authenticate(); $identity = $this->getAuth()->getIdentity(); } } return $identity; } return false; } public function addItem($item, $groupName = null) { if (null === $groupName) { $groupName = $this->getGroupName(); } if ($item instanceof Qs_Doc_Item) { $docItem = $item; } else { $docItem = new Qs_Doc_Item($item); } $this->addItemResources($docItem); $this->_content[$groupName][] = $docItem; return $this; } public function getGroupName() { if (null === $this->_groupName) { return $this->_defaultGroupName; } return $this->_groupName; } public function unsetGroupName() { $this->_groupName = null; return $this; } public function setGroupName($groupName) { $this->_groupName = $groupName; return $this; } public function addReadyFunction($name, $params = []) { $this->_content['head']['readyFunctions'][] = [ 'name' => $name, 'params' => $params, ]; return $this; } public function addReadyObject($name, $params = [], $assign = null) { $this->_content['head']['readyFunctions'][] = [ 'name' => $name, 'params' => $params, 'assign' => $assign, 'new' => true, ]; return $this; } public function addInitFunction($name, $params = []) { $this->_content['head']['initFunctions'][] = [ 'name' => $name, 'params' => $params, ]; return $this; } public function addInitObject($name, $params = [], $assign = null) { $this->_content['head']['initFunctions'][] = [ 'name' => $name, 'params' => $params, 'assign' => $assign, 'new' => true, ]; return $this; } public function getTemplate($template, $logNotFound = true) { return Qs_SiteMap::getTemplate($template, $this->getTemplatePath(), $logNotFound); } public function getTemplatePath() { if (null === $this->_templatePath) { $class = get_class($this); $this->_templatePath = substr($class, 0, strrpos($class, '_')); if (0 === strpos($this->_templatePath, 'App_')) { $this->_templatePath = substr($this->_templatePath, 4); } } return $this->_templatePath; } /** * @return Smarty */ public function getSmarty() { if (null === $this->_smarty) { if (!class_exists('Smarty')) { require_once 'lib/Smarty/Smarty/Smarty.class.php'; } $this->_smarty = new Smarty(); $this->_smarty->compile_check = true; $this->_smarty->debugging = false; $this->_smarty->template_dir = $this->getTemplateDirectory(); $this->_smarty->cache_lifetime = 40; $this->_smarty->force_compile = false; $this->_smarty->php_handling = SMARTY_PHP_PASSTHRU; $this->_smarty->compile_dir = Qs_Constant::get('BASE_PATH') . '/tmp/tpl_c'; $this->_smarty->left_delimiter = '{'; $this->_smarty->right_delimiter = '}'; foreach ($this->_smartyPlugins['block'] as $name => $block) { $this->_smarty->_plugins['block'][$name] = $block; } foreach ($this->_smartyPluginPaths as $dir) { $this->_smarty->plugins_dir[] = Qs_Constant::get('BASE_PATH') . '/' . $dir; } } return $this->_smarty; } protected function _createItemObj($item) { $separator = (false !== strpos($item['type'], '\\')) ? '\\' : '_'; $class = Qs_SiteMap::getItemTypeClass($item['type'], 'View'); $file = BASE_PATH . '/' . str_replace($separator, '/', $class) . '.php'; if (!file_exists($file)) { Qs_Debug::log('Cms item "' . $item['type'] . '" not found'); return false; } $item['doc'] = $this; if (array_key_exists('id', $item)) { $item['idItem'] = $item['id']; } return new $class($item); } public function renderPageItems($items) { $itemObj = []; $_pageItems = $items; $indexes = array_keys($items); while (false !== ($index = current($indexes)) && array_key_exists($index, $items)) { next($indexes); $item = $items[$index]; next($items); /** @var $obj Qs_ViewController */ if (false !== ($obj = $this->_createItemObj($item))) { $itemObj[$index] = $obj; } else { continue; } if (method_exists($itemObj[$index], 'preDispatch')) { $itemObj[$index]->preDispatch($items); } } foreach ($items as $index => $item) { if (array_key_exists($index, $itemObj)) { $obj = $itemObj[$index]; } else { if (false === ($obj = $this->_createItemObj($item))) { continue; } } if (isset($items[$index]['groupName'])) { $this->setGroupName($items[$index]['groupName']); } else { $this->unsetGroupName(); } $time = microtime(true); $obj->exec(); unset($itemObj[$index]); if (Qs_Constant::get('DEBUG')) { $_pageItems[$index]['executed'] = true; $_pageItems[$index]['duration'] = round((microtime(true) - $time) * 1000); } } if (Qs_Constant::get('DEBUG')) { Zend_Registry::set('_pageItems', $_pageItems); } return $this; } public function registerSmartyBlock($block, $block_impl, $cacheable = true, $cache_attrs = null) { $this->_smartyPlugins['block'][$block] = [$block_impl, null, null, false, $cacheable, $cache_attrs]; return $this; } public function removeItem($index, $groupName = null) { if (null === $groupName) { $groupName = $this->getGroupName(); } if (array_key_exists($index, $this->_content[$groupName])) { unset($this->_content[$groupName][$index]); } return $this; } public function setBodyAttribs($attribs) { $this->_content['bodyAttribs'] = $attribs; } public function setBodyAttrib($name, $value) { $this->_content['bodyAttribs'][$name] = $value; } public function getBodyAttribs() { return $this->_content['bodyAttribs']; } public function getMenu() { return $this->_content['menu']; } public function getCtrlMenu() { if (null === $this->_content['ctrlMenu']) { $filter = ['showInCtrlMenu' => 'y', 'requireSu' => 'n']; if ($this->hasAuth() && $this->getAuth()->getSuMode()) { unset($filter['requireSu']); } $ctrlMenu = Qs_SiteMap::find($filter); $this->_prepareCtrlMenu($ctrlMenu, $filter); $this->_content['ctrlMenu'] = $ctrlMenu; } return $this->_content['ctrlMenu']; } protected function _prepareCtrlMenu(array &$menu, array $filter) { if (!empty($menu)) { foreach ($menu as $key => &$item) { if (!empty($filter['requireSu']) && $filter['requireSu'] != $item['requireSu']) { unset($menu[$key]); } else if (!empty($item['sub'])) { $this->_prepareCtrlMenu($item['sub'], $filter); } } $menu = array_merge($menu); } return $this; } public function getBodyAttrib($name) { if (array_key_exists($name, $this->_content['bodyAttribs'])) { return $this->_content['bodyAttribs'][$name]; } return null; } public function renderScripts($excludedAttribs = null) { $html = ''; foreach ($this->_content['head']['script'] as $attribs) { if (!empty($excludedAttribs)) { if (is_array($excludedAttribs)) { foreach ($excludedAttribs as $excluded) { unset($attribs[$excluded]); } } else { unset($attribs[$excludedAttribs]); } } if (0 === strpos($attribs['src'], 'js/')) { if (Qs_Constant::get('SITE_REVISION')) { $attribs['src'] = BASE_URL . '/js-' . Qs_Constant::get('SITE_REVISION') . '/' . substr($attribs['src'], 3); } else { $attribs['src'] = BASE_URL . '/' . $attribs['src']; } } $html .= '' . "\n "; } return $html; } public function renderStylesheets() { $html = ''; foreach ($this->_content['head']['stylesheet'] as $attribs) { if (Qs_Constant::get('SITE_REVISION')) { if (0 === strpos($attribs['href'], 'css/')) { $attribs['href'] = 'css-' . Qs_Constant::get('SITE_REVISION') . '/' . substr($attribs['href'], 4); } } $html .= ' $value) { $html .= ' ' . $name . ' = "' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '"'; } $html .= '/>' . "\n "; } return $html; } public function renderInlineScripts($indents = null, $beforeScripts = false) { $html = ''; $scriptsHtml = []; $indents = (!$indents) ? 1 : $indents; $indent = str_repeat(' ', $indents * 4); $beforeScripts = (int) $beforeScripts; if (is_array($this->_content['head']['inlineScript'][$beforeScripts])) { foreach ($this->_content['head']['inlineScript'][$beforeScripts] as $name => $script) { $attribs = ''; foreach ($script['attribs'] as $attribute => $attributeValue) { $attribs .= $attribute . ' = "' . htmlspecialchars($attributeValue, ENT_COMPAT, 'UTF-8') . '" '; } $attribs = trim($attribs); $body = PHP_EOL . '/* Inline Script: ' . $name . ' */' . PHP_EOL . $script['body']; $scriptsHtml[$attribs] .= str_replace(PHP_EOL, PHP_EOL . $indent . $indent, $body) . PHP_EOL; } foreach ($scriptsHtml as $scriptAttribs => $scriptHtml) { $html = ''; } } return $html; } protected function _renderInitFunctions(array $functionsSpec = null) { $functionsSpec = (null === $functionsSpec) ? $this->_content['head']['initFunctions'] : $functionsSpec; $html = ''; foreach ($functionsSpec as $options) { $row = $options['name']; if (!empty($options['params'])) { $params = []; foreach ($options['params'] as $param) { $json = Zend_Json::encode($param, false, ['enableJsonExprFinder' => true]); if (constant('DEBUG')) { $json = Zend_Json::prettyPrint($json, ['indent' => ' ']); $json = str_replace("\n", "\n" . str_repeat(' ', 2), $json); } $params[] = $json; } $row .= '(' . implode(', ', $params) . ');'; } else { $row .= '();'; } if (isset($options['new']) && $options['new']) { $row = 'new ' . $row; } if (!empty($options['assign'])) { $row = $options['assign'] . ' = ' . $row; } $html .= str_repeat(' ', 2) . $row . "\n\n"; } return $html; } public function renderInitFunctions() { return $this->_renderInitFunctions($this->_content['head']['initFunctions']); } public function renderReadyFunctions() { return $this->_renderInitFunctions($this->_content['head']['readyFunctions']); } function setTemplatePath($path) { $this->_templatePath = $path; return $this; } public function getUserRole() { $role = null; if ($this->hasAuth()) { $role = $this->getAuth()->getRole(); } return $role; } public function getUserId() { $id = null; if ($this->hasAuth()) { $id = $this->getAuth()->getData('id'); } return $id; } public function getLockObj() { if (null === $this->_lockObj) { $this->_lockObj = new Qs_Lock_RoleObj($this->getUserRole(), $this->getUserId(), Zend_Session::getId()); } return $this->_lockObj; } public function setHtmlAttribs(array $attribs) { if (!is_array($attribs) || !Qs_Array::isAssoc($attribs)) { throw new Qs_Exception('Attribs is not associative array'); } $this->_content['htmlAttribs'] = $attribs; return $this; } public function setHtmlAttrib($name, $value) { if (!is_string($name) || '' == $name) { throw new Qs_Exception('Wrong attribute name'); } if (!is_string($value) || '' == $value) { throw new Qs_Exception('Wrong attribute value'); } $this->_content['htmlAttribs'][$name] = $value; return $this; } public function getHtmlAttrib($name) { return isset($this->_content['htmlAttribs'][$name]) ? $this->_content['htmlAttribs'][$name] : null; } public function getHtmlAttribs() { return $this->_content['htmlAttribs']; } public function addItemResources(Qs_Doc_Item $item) { $resources = ['script', 'inlineScript', 'stylesheet', 'readyFunction', 'initFunction', 'initObject']; foreach ($resources as $name) { if (isset($item->{$name}) && is_array($item->{$name})) { foreach ($item->{$name} as $params) { call_user_func_array([$this, 'add' . ucfirst($name)], (array) $params); } } } return $this; } public function addResources(array $resources) { foreach ($resources as $type => $list) { $method = 'add' . $type; if (method_exists($this, $method)) { foreach ($list as $arguments) { call_user_func_array([$this, $method], $arguments); } } else { trigger_error('Undefined resource type'); } } return $this; } public function getResources() { $script = ''; $head = $this->getTemplateVariable('head'); foreach ($head['inlineScript'] as $inlineScript) { $script .= "{$inlineScript}\n"; } $script .= "\n" . $this->renderReadyFunctions(); $script .= "\n" . $this->renderInitFunctions(); return $script; } public function sendNoindexHeader() { header('X-Robots-Tag: noindex, nofollow'); return $this; } public function setPagePreviewMode($value = true) { $this->_isPagePreviewMode = $value; return $this; } public function isPagePreviewMode() { return $this->_isPagePreviewMode; } public function getWidgets($placement = null, $default = null) { return Qs_Array::get($this->_widgets, $placement, $default); } public function setWidgets(array $widgets) { $this->_widgets = $widgets; return $this; } public function renderWidgets($placement) { return $this->getWidgets($placement, ''); } public function getModulePlaceholders($module = null) { return Qs_Array::get($this->_modulePlaceholders, $module, []); } public function setModulePlaceholders($module, $placeholders) { $this->_modulePlaceholders[$module] = $placeholders; return $this; } public function hasModulePlaceholders($module) { return array_key_exists($module, $this->_modulePlaceholders); } public function renderMeta() { $html = ''; foreach ($this->_content['head']['meta'] as $attribs) { $html .= Qs\Html::renderTag('meta', $attribs) . ' '; } return $html; } public function addMeta($attribs = []) { $this->_content['head']['meta'][] = $attribs; return $this; } }