'site', ]; protected static $_siteMapXml; protected static $_siteMapDb; protected static $_siteMapMenu; protected static $_siteMapFooter; protected static $_siteMapUserend; protected static $_siteMapBackendFull; protected static $_siteMapBackendMenu; protected static $_fullSitemap; protected static function _getFromXml($file = 'sitemap.xml') { if (null === Qs_SiteMap::$_siteMapXml) { $config = new Zend_Config_Xml(BASE_PATH . '/' . $file); $siteMap = $config->toArray(); Qs_SiteMap::$_siteMapXml = Qs_SiteMap::_prepareSiteMapXml($siteMap); } return Qs_SiteMap::$_siteMapXml; } public static function reload($file) { Qs_SiteMap::$_siteMapXml = null; Qs_SiteMap::$_siteMapBackendMenu = null; Qs_SiteMap::_getFromXml($file); } public static function loadXml($file = 'sitemap.xml') { Qs_SiteMap::_getFromXml($file); } public static function getFromDb($options = []) { return Qs_SiteMap::_getFromDb($options); } protected static function _getFromDb($options = []) { if (array_key_exists('select', $options)) { return App_Cms_Obj::getInstance()->getSiteMap($options); } if (null === Qs_SiteMap::$_siteMapDb) { Qs_SiteMap::$_siteMapDb = App_Cms_Obj::getInstance()->getSiteMap(); } if (empty($options)) { return Qs_SiteMap::$_siteMapDb; } else { if (empty($options['filter']) || !is_array($options['filter'])) { $options['filter'] = []; } if (!empty($options['idParent'])) { $siteMap = Qs_Array::treeBranch(Qs_SiteMap::$_siteMapDb, $options['idParent']); } else { $siteMap = Qs_SiteMap::$_siteMapDb; } return Qs_SiteMap::_siteMapFilter($siteMap, $options); } } /** * Example: * * $filtered = Qs_SiteMap::_siteMapFilter( * Qs_SiteMap::$_siteMapDb, * array( * 'filter' => array('system' => 'n', 'showInSiteMap' => 'y'), * 'idParent' => 6, * ) * ); * * @param array $siteMap * @param array $options * @return array */ protected static function _siteMapFilter(array $siteMap, array $options) { $tree = []; foreach ($siteMap as $key => $page) { if (!array_diff_assoc($options['filter'], $page)) { $tree[$key] = $page; $sub = Qs_Array::get($page, 'sub', []); if ($sub) { unset($tree[$key]['sub']); $tree[$key]['sub'] = Qs_SiteMap::_siteMapFilter($sub, $options); } } } return $tree; } protected static function _prepareSiteMapXmlPage(&$page, $fullAlias = '', $parent = null) { $page['source'] = 'xml'; $parent = $parent ? Qs_Array::map($parent, array_keys(self::$_defaults)) : self::$_defaults; $page = array_merge($parent, $page); if (isset($page['item'])) { if (Qs_Array::isAssoc($page['item'])) { $page['items'] = [$page['item']]; } else { $page['items'] = $page['item']; } unset($page['item']); } if (!isset($page['header']) || empty($page['header'])) { $page['header'] = Qs_Array::get($page, 'menuTitle'); } if (!isset($page['title']) || empty($page['title'])) { $page['title'] = Qs_Array::get($page, 'menuTitle'); } $page['fullAlias'] = $fullAlias; $page['alias'] = basename($fullAlias); if (Qs_SiteMap::isSecurePage($page)) { $page['url'] = BASE_URL_LANGUAGE_HTTPS . ((empty($page['fullAlias'])) ? '' : '/') . $page['fullAlias']; } else { $page['url'] = BASE_URL_LANGUAGE_HTTP . ((empty($page['fullAlias'])) ? '' : '/') . $page['fullAlias']; } if (isset($page['sub'])) { $page['sub'] = Qs_SiteMap::_prepareSiteMapXml($page['sub'], $page); } } protected static function _prepareSiteMapXml($siteMap, $parent = null) { if (method_exists(App_Cms_Obj::getInstance(), 'getDefaultMetaPairs')) { $defaultMetaValues = App_Cms_Obj::getInstance()->getDefaultMetaPairs(); } else { $defaultMetaValues = []; Qs_Debug::log('App_Cms_Obj::getDefaultMetaPairs() is not defined. ' . 'Please update your App_Cms_Obj class mamualy.'); } foreach ($siteMap as $alias => &$page) { if (!is_array($page)) { continue; } Qs_SiteMap::_prepareSiteMapXmlPage($page, (($parent) ? $parent['fullAlias'] . '/' : '') . $alias, $parent); $page = array_merge($defaultMetaValues, (array) $page); } return $siteMap; } /** * @param string $page * @return bool|null * @throws Qs_Exception */ public static function isSecurePage($page) { if (is_string($page)) { $alias = $page; if (0 === strpos($alias, BASE_URL_HTTP)) { $alias = (string) substr($alias, strlen(BASE_URL_HTTP) + 1); } elseif (0 === strpos($alias, BASE_URL_HTTPS)) { $alias = (string) substr($alias, strlen(BASE_URL_HTTPS) + 1); } else { return null; } if (!is_array($page = Qs_SiteMap::getPage($alias, false, null))) { return null; } } elseif (!is_array($page)) { throw new Qs_Exception('invalid page parameter'); } return (isset($page['isSecure']) && $page['isSecure'] == 'y'); } public static function getPage($alias, $breakIfFinal = true, $defaults = null) { if (!($siteMap = Qs_SiteMap::getFull())) { return Qs_SiteMap::NOT_FOUND; } if (null === $defaults) { $defaults = Qs_SiteMap::$_defaults; } if (empty($alias)) { // home page return current($siteMap); } $page = Qs_SiteMap::_getPageEx($alias, $siteMap, $breakIfFinal, $defaults); if (!is_array($page)) { return $page; } if ('y' == $page['final']) { if (null !== ($_page = self::_getSubFinal($page))) { $page = array_merge($defaults, $_page); } } if (isset($page['_restAlias'])) { Qs_SiteMap::setRestAlias($page, $page['_restAlias']); unset($page['_restAlias']); } return $page; } protected static function _getSubFinal(array $page) { if (empty($page['_restAlias'])) { return null; } $restParams = explode('/', $page['_restAlias']); $subAlias = array_shift($restParams); if (isset($page['sub']) && is_array($page['sub']) && array_key_exists($subAlias, $page['sub']) && 'y' == $page['sub'][$subAlias]['final'] ) { $page = $page['sub'][$subAlias]; $page['_restAlias'] = implode('/', $restParams); if (null !== ($_page = self::_getSubFinal($page))) { return $_page; } return $page; } return null; } public static function filter($siteMap, $filter) { return Qs_SiteMap::_filter($siteMap, $filter); } protected static function _filter($siteMap, $filter) { foreach ($siteMap as $alias => &$page) { foreach ($filter as $field => $value) { if (!(isset($page[$field]) && $page[$field] == $value)) { unset($siteMap[$alias]); continue 2; } } if (isset($page['sub']) && !empty($page['sub'])) { $page['sub'] = Qs_SiteMap::_filter($page['sub'], $filter); } } return $siteMap; } public static function prepareMobileMenu(array &$menu, $appendItem = null) { foreach ($menu as &$menuItem) { if (array_key_exists('sub', $menuItem) && $menuItem['sub']) { $parentItem = null; $hasItems = (array_key_exists('items', $menuItem) && $menuItem['items']); $hasPageRedirect = ('y' == $menuItem['redirect'] && 'page' == Qs_Array::get($menuItem, 'redirectType')); if ($hasItems && !$hasPageRedirect || (!$hasItems && !$hasPageRedirect)) { $parentItem = $menuItem; unset($parentItem['sub']); } $menuItem['url'] = '#'; self::prepareMobileMenu($menuItem['sub'], $parentItem); } } if ($appendItem) { $menu = [$appendItem['fullAlias'] => $appendItem] + $menu; } return true; } public static function getMenu() { if (null === Qs_SiteMap::$_siteMapMenu) { Qs_SiteMap::$_siteMapMenu = Qs_SiteMap::filter(self::getFull(), ['showInMenu' => 'y', 'enabled' => 'y']); } return Qs_SiteMap::$_siteMapMenu; } public static function getFooter() { if (null === Qs_SiteMap::$_siteMapFooter) { Qs_SiteMap::$_siteMapFooter = Qs_SiteMap::filter(self::getFull(), ['showInFooter' => 'y', 'enabled' => 'y']); } return Qs_SiteMap::$_siteMapFooter; } public static function get4Userend() { if (null === Qs_SiteMap::$_siteMapUserend) { Qs_SiteMap::$_siteMapUserend = Qs_SiteMap::filter(self::getFull(), ['showInSiteMap' => 'y', 'enabled' => 'y']); } return Qs_SiteMap::$_siteMapUserend; } public static function getBackendSiteMapFull() { if (null === Qs_SiteMap::$_siteMapBackendFull) { $siteMap = Qs_SiteMap::_getFromXml(); Qs_SiteMap::$_siteMapBackendFull = ['admin' => $siteMap['admin']]; } return Qs_SiteMap::$_siteMapBackendFull; } public static function getBackendMenu() { if (null === Qs_SiteMap::$_siteMapBackendMenu) { $siteMap = Qs_SiteMap::_getFromXml(); Qs_SiteMap::$_siteMapBackendMenu = Qs_SiteMap::_filter($siteMap['admin']['sub'], ['showInMenu' => 'y']); } return Qs_SiteMap::$_siteMapBackendMenu; } protected static function _getPageEx($_alias, $siteMap, $breakIfFinal = true, $defaults = []) { $parts = explode('/', $_alias); $alias = array_shift($parts); $restAlias = implode('/', $parts); if (isset($siteMap[$alias])) { if ($siteMap[$alias]['enabled'] == 'n') { return Qs_SiteMap::NOT_FOUND; } if (!strlen($restAlias)) { if (empty($parts)) { return array_merge($defaults, $siteMap[$alias]); } return Qs_SiteMap::ENDS_WITH_SLASH; } if (isset($siteMap[$alias]['final']) && $siteMap[$alias]['final'] == 'y' && $breakIfFinal) { $page = array_merge($defaults, $siteMap[$alias]); $page['_restAlias'] = $restAlias; $partsCount = count($parts); if (2 <= $partsCount && empty($parts[$partsCount - 1])) { return Qs_SiteMap::ENDS_WITH_SLASH; } return $page; } if (isset($restAlias[0]) && $restAlias[0] == '/') { return Qs_SiteMap::NOT_FOUND; } if (isset($siteMap[$alias]['sub'])) { $_defaults = array_intersect_key(array_merge($defaults, $siteMap[$alias]), $defaults); return Qs_SiteMap::_getPageEx($restAlias, $siteMap[$alias]['sub'], $breakIfFinal, $_defaults); } } return Qs_SiteMap::NOT_FOUND; } public static function setRestAlias(&$page, $restAlias) { if (isset($page['items'])) { foreach ($page['items'] as &$item) { $item['restAlias'] = $restAlias; } } } public static function get404Page() { return [ 'title' => '404 Not Found', 'handler' => 'speedy', 'items' => [['type' => 'NotFound_']], ]; } public static function templateExists($template) { if (file_exists($template) && is_file($template)) { return true; } return false; } public static function getTemplate($template, $templatePath = null) { if (null !== $templatePath) { if (is_array($templatePath)) { foreach ($templatePath as $path) { $templateName = BASE_PATH . '/tpl/' . $path . '/' . $template; if (Qs_SiteMap::templateExists($templateName)) { return $templateName; } } return false; } else { $applicationFileName = BASE_PATH . '/tpl/' . $templatePath . '/' . $template; if (Qs_SiteMap::templateExists($applicationFileName)) { return $applicationFileName; } } } $commonFileName = BASE_PATH . '/tpl/' . $template; if (Qs_SiteMap::templateExists($commonFileName)) { return $commonFileName; } return false; } protected static function getCacheFile() { return BASE_PATH . '/tmp/cache-sitemap-' . CURRENT_LANGUAGE . '.php'; } public static function clearCache() { $file = self::getCacheFile(); if (file_exists($file)) { unlink($file); } } public static function getFull() { if (null === Qs_SiteMap::$_fullSitemap) { $file = self::getCacheFile(); if (file_exists($file)) { Qs_SiteMap::$_fullSitemap = include($file); return Qs_SiteMap::$_fullSitemap; } Qs_SiteMap::loadXml(); Qs_SiteMap::$_fullSitemap = App_Cms_Obj::getInstance()->getSiteMap(); Qs_SiteMap::$_fullSitemap = array_merge(Qs_SiteMap::$_fullSitemap, Qs_SiteMap::$_siteMapXml); file_put_contents( $file, ' 'News_'), array('type' => 'default'), 'fullAlias'); * - Qs_SiteMap::find('(final=y)(isSecure=y)[type=default]', 'fullAlias'); * * String selector structure: [page options](item options){config} */ public static function findFirst($page = null, $item = null, $config = null, $field = null, $siteMap = null) { if (false !== ($result = Qs_SiteMap::find($page, $item, $config, $field, 1, $siteMap))) { if (is_string($page)) { $field = (is_string($item)) ? $item : null; } return (null === $field) ? reset($result) : $result; } return $result; } /** * Find pages (or page's column) that match the page options, item options or item config. * If field set - return just field of first item from result * @static * @param array|string|null $page [OPTIONAL] page options or string selector * @param array|null $item [OPTIONAL] item options * @param array|null $config [OPTIONAL] item config options * @param string|null $field [OPTIONAL] field of the page that be returned * @param int|null $limit [OPTIONAL] result limit * @param array|null $siteMap [OPTIONAL] context to search in * @return mixed|bool list of pages with matched options or result value (if $field is defined) */ public static function find($page = null, $item = null, $config = null, $field = null, $limit = null, $siteMap = null) { $result = static::_findAllPages($page, $item, $config, $field, $limit, $siteMap); if (empty($result)) { return false; } return (isset($field)) ? Qs_Array::get(reset($result), $field) : $result; } /** * Find pages (or page's column) that match the page options, item options or item config. * @static * @param array|string|null $page [OPTIONAL] page options or string selector * @param array|null $item [OPTIONAL] item options * @param array|null $config [OPTIONAL] item config options * @param string|null $field [OPTIONAL] field of the page that be returned * @param int|null $limit [OPTIONAL] result limit * @param array|null $siteMap [OPTIONAL] context to search in * @return mixed|bool list of pages with matched options or result value (if $field is defined) */ public static function findAll($page = null, $item = null, $config = null, $field = null, $limit = null, $siteMap = null) { $result = static::_findAllPages($page, $item, $config, $field, $limit, $siteMap); if (empty($result)) { return false; } return (isset($field)) ? Qs_Array::fetchCol($result, $field) : $result; } /** * Find pages that match the page options, item options or item config. * @static * @param array|string|null $page [OPTIONAL] page options or string selector * @param array|null $item [OPTIONAL] item options * @param array|null $config [OPTIONAL] item config options * @param string|null $field [OPTIONAL] field of the page that be returned * @param int|null $limit [OPTIONAL] result limit * @param array|null $siteMap [OPTIONAL] context to search in * @return mixed|bool list of pages with matched options or result value (if $field is defined) */ protected static function _findAllPages($page = null, $item = null, $config = null, &$field = null, $limit = null, $siteMap = null) { if (is_string($page)) { $selector = $page; $field = (is_string($item)) ? $item : null; $page = Qs_SiteMap::_selectorToArray($selector, '/\(([^\)]+)\)/'); $item = Qs_SiteMap::_selectorToArray($selector, '/\<([^\>]+)\>/'); $config = Qs_SiteMap::_selectorToArray($selector, '/\[([^\]]+)\]/'); } else { $page = (is_array($page)) ? $page : []; $item = (is_array($item)) ? $item : []; $config = (is_array($config)) ? $config : []; } $siteMap = (null === $siteMap) ? Qs_SiteMap::getFull() : $siteMap; if (empty($siteMap) || !is_array($siteMap) || (empty($page) && empty($item) && empty($config))) { return false; } $result = []; Qs_SiteMap::_find($siteMap, $page, $item, $config, $result, (null !== $field) ? 1 : $limit); if (empty($result)) { return false; } return $result; } protected static function _selectorToArray($selector, $pattern) { $matches = []; preg_match_all($pattern, $selector, $matches); $result = []; if (isset($matches[1])) { foreach ($matches[1] as $string) { $parts = explode('=', $string); $name = array_shift($parts); $value = array_shift($parts); $result[$name] = $value; } } return $result; } protected static function _find(&$siteMap, $page, $item, $config, &$result, $limit = null) { foreach ($siteMap as &$_page) { if (self::match($_page, $page, $item, $config)) { $result[] = $_page; } if (isset($_page['sub']) && (null === $limit || $limit > count($result))) { Qs_SiteMap::_find($_page['sub'], $page, $item, $config, $result); } } } public static function &findFirstEditable(&$siteMap, $page = [], $item = [], $config = []) { foreach ($siteMap as &$_page) { if (self::match($_page, $page, $item, $config)) { return $_page; } if (isset($_page['sub'])) { if (false !== ($result = &self::findFirstEditable($_page['sub'], $page, $item, $config))) { return $result; } } } $result = false; return $result; } protected static function match(array $page, $pageQuery = [], $item = [], $config = []) { $diff = array_diff_assoc($pageQuery, $page); if (!empty($diff)) { return false; } if (empty($item) && empty($config)) { return true; } $page['items'] = (isset($page['items'])) ? $page['items'] : []; foreach ($page['items'] as &$_item) { $diff = array_diff_assoc($item, $_item); if (empty($diff)) { $_config = (array) Qs_Array::get($_item, 'config'); $diff = array_diff_assoc($config, $_config); if (empty($diff)) { return true; } } } return false; } public static function &getEditablePage($page = [], $item = [], $config = []) { self::getFull(); $siteMap = &Qs_SiteMap::$_fullSitemap; $result = &self::findFirstEditable($siteMap, $page, $item, $config); return $result; } public static function getAliasByItem($type) { if (false !== ($page = Qs_SiteMap::findFirst([], ['type' => $type]))) { if (isset($page['isRoot']) && 'y' == $page['isRoot']) { return ''; } return $page['fullAlias']; } return false; } public static function createPageItemView($item) { $separator = (false !== strpos($item['type'], '\\')) ? '\\' : '_'; $class = 'App' . $separator . $item['type'] . 'View'; $file = BASE_PATH . '/' . str_replace(['_', '\\'], '/', $class) . '.php'; if (!file_exists($file)) { Qs_Debug::log('Page item "' . $item['type'] . '" not found'); return false; } if (array_key_exists('id', $item)) { $item['idItem'] = $item['id']; } return new $class($item); } public static function getSubClass($classNamePrefix, $suffix) { $separator = (false !== strpos($classNamePrefix, '\\')) ? '\\' : '_'; return $classNamePrefix . str_replace('_', $separator, $suffix); } public static function getItemTypeClass($type, $suffix) { $separator = (false !== strpos($type, '\\')) ? '\\' : '_'; return 'App' . $separator . $type . $suffix; } /** * "App\Cms\View" => "Cms\" * @param string|\Qs_ViewController $class * @return string */ public static function classToType($class) { $class = (is_object($class)) ? get_class($class) : (string) $class; if ('App' === substr($class, 0, 3) && 'View' === substr($class, -4)) { $class = substr(substr($class, 4), 0, -4); } return $class; } /** * @param string|\Qs_ViewController $class * @return string */ public static function classToPath($class) { $class = (is_object($class)) ? get_class($class) : (string) $class; $path = str_replace(['_', '\\'], '/', $class); if ('App/' === substr($path, 0, 4)) { $path = substr($path, 4); $path = substr($path, 0, strrpos($path, '/')); } return rtrim($path, '/'); } public static function classToId($class) { return str_replace('/', '-', strtolower(self::classToPath($class))); } public static function getDefaults() { return self::$_defaults; } public static function setDefaults(array $defaults) { self::$_defaults = $defaults; } } function SMGetTemplate($template, $templatePath = null) { return Qs_SiteMap::getTemplate($template, $templatePath); } function SMGetAliasByItem($type) { return Qs_SiteMap::getAliasByItem($type); }