'site', 'isSecure' => 'n', ); 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 = array()) { return Qs_SiteMap::_getFromDb($options); } protected static function _getFromDb($options = array()) { 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'] = array(); } 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 = array(); foreach ($siteMap as $key => $page) { if (!array_diff_assoc($options['filter'], $page)) { $tree[$key] = $page; $sub = Qs_Array::get($page, 'sub', array()); if ($sub) { unset($tree[$key]['sub']); $tree[$key]['sub'] = Qs_SiteMap::_siteMapFilter($sub, $options); } } } return $tree; } protected static function _prepareSiteMapXmlPage(&$page, $fullAlias = '') { $page['source'] = 'xml'; if (isset($page['item'])) { if (Qs_Array::isAssoc($page['item'])) { $page['items'] = array($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['fullAlias']); } } protected static function _prepareSiteMapXml($siteMap, $parentAlias = null) { if (method_exists(App_Cms_Obj::getInstance(), 'getDefaultMetaPairs')) { $defaultMetaValues = App_Cms_Obj::getInstance()->getDefaultMetaPairs(); } else { $defaultMetaValues = array(); 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, (($parentAlias) ? $parentAlias . '/' : '') . $alias); $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, false))) { 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, $loadItems = true) { $siteMap = Qs_SiteMap::_getFromXml(); if (null === $defaults) { $defaults = Qs_SiteMap::$_defaults; } $page = Qs_SiteMap::_getPageEx($alias, $siteMap, $breakIfFinal, $defaults); if ($page == Qs_SiteMap::NOT_FOUND) { $siteMap = Qs_SiteMap::_getFromDb(); if (empty($alias) && !empty($siteMap)) { foreach ($siteMap as $page) { if ($page['enabled'] != 'n') { $alias = $page['alias']; break; } } } if (is_array($page = Qs_SiteMap::_getPageEx($alias, $siteMap, $breakIfFinal, $defaults))) { $page = Qs_Array::excludeKey($page, 'sub'); if ($loadItems) { // load items, keywords and description $metaData = App_Cms_Obj::getInstance()->getMeta($page['id']); $filterFunction = function ($value) { if (is_scalar($value)) { return (bool) strlen($value); } else { return !empty($value); } }; $metaData = array_filter($metaData, $filterFunction); $page = array_merge($page, $metaData); $page['items'] = App_Cms_Obj::getInstance()->getItemsList($page['id']); } } } if (is_array($page)) { if (isset($page['_restAlias'])) { Qs_SiteMap::_setRestAlias($page, $page['_restAlias']); unset($page['_restAlias']); } } return $page; } 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 = array($appendItem['fullAlias'] => $appendItem) + $menu; } return true; } public static function getMenu() { if (null === Qs_SiteMap::$_siteMapMenu) { Qs_SiteMap::$_siteMapMenu = Qs_SiteMap::_getFromDb( array('filter' => array('showInMenu' => 'y', 'enabled' => 'y')) ); } return Qs_SiteMap::$_siteMapMenu; } public static function getFooter() { if (null === Qs_SiteMap::$_siteMapFooter) { Qs_SiteMap::$_siteMapFooter = Qs_SiteMap::_getFromDb( array('filter' => array('showInFooter' => 'y', 'enabled' => 'y')) ); } return Qs_SiteMap::$_siteMapFooter; } public static function get4Userend() { if (null === Qs_SiteMap::$_siteMapUserend) { Qs_SiteMap::$_siteMapUserend = Qs_SiteMap::_getFromDb( array('filter' => array('showInSiteMap' => 'y', 'enabled' => 'y')) ); } return Qs_SiteMap::$_siteMapUserend; } public static function getBackendSiteMapFull() { if (null === Qs_SiteMap::$_siteMapBackendFull) { $siteMap = Qs_SiteMap::_getFromXml(); Qs_SiteMap::$_siteMapBackendFull = array('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'], array('showInMenu' => 'y')); } return Qs_SiteMap::$_siteMapBackendMenu; } protected static function _getPageEx($_alias, $siteMap, $breakIfFinal = true, $defaults = array()) { $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; } protected static function _setRestAlias(&$page, $restAlias) { if (isset($page['items'])) { foreach ($page['items'] as &$item) { $item['restAlias'] = $restAlias; } } } public static function get404Page() { return array( 'title' => '404 Not Found', 'handler' => 'speedy', 'items' => array(array('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; } public static function getFull() { if (null === Qs_SiteMap::$_fullSitemap) { Qs_SiteMap::loadXml(); Qs_SiteMap::$_fullSitemap = App_Cms_Obj::getInstance()->getSiteMap(); if (($firstAlias = key(Qs_SiteMap::$_fullSitemap))) { if (!empty(Qs_SiteMap::$_fullSitemap[$firstAlias]['sub'])) { Qs_SiteMap::$_fullSitemap[$firstAlias]['sub'] = array_merge( Qs_SiteMap::$_fullSitemap[$firstAlias]['sub'], Qs_SiteMap::$_siteMapXml ); } else { Qs_SiteMap::$_fullSitemap[$firstAlias]['sub'] = Qs_SiteMap::$_siteMapXml; } } else { Qs_SiteMap::$_fullSitemap = Qs_SiteMap::$_siteMapXml; } } return Qs_SiteMap::$_fullSitemap; } /** * Find first page 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 array|null $siteMap [OPTIONAL] context to search in * @return mixed|bool list of pages with matched options or result value (if $field is defined) * * Examples: * - Qs_SiteMap::find(null, array('type' => '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 : array(); $item = (is_array($item)) ? $item : array(); $config = (is_array($config)) ? $config : array(); } $siteMap = (null === $siteMap) ? Qs_SiteMap::getFull() : $siteMap; if (empty($siteMap) || !is_array($siteMap) || (empty($page) && empty($item) && empty($config))) { return false; } $result = array(); 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 = array(); preg_match_all($pattern, $selector, $matches); $result = array(); 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) { $diff = array_diff_assoc($page, $_page); if (empty($diff)) { if (empty($item) && empty($config)) { $result[] = $_page; } else { $_page['items'] = (isset($_page['items'])) ? $_page['items'] : array(); 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)) { $result[] = $_page; } } } } } if (isset($_page['sub']) && (null === $limit || $limit > count($result))) { Qs_SiteMap::_find($_page['sub'], $page, $item, $config, $result); } } } public static function getAliasByItem($type) { if (false !== ($page = Qs_SiteMap::findFirst(array(), array('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(array('_', '\\'), '/', $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(array('_', '\\'), '/', $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))); } } function SMGetTemplate($template, $templatePath = null) { return Qs_SiteMap::getTemplate($template, $templatePath); } function SMGetAliasByItem($type) { return Qs_SiteMap::getAliasByItem($type); }