energine
[ class tree: energine ] [ index: energine ] [ all elements ]

Source for file Sitemap.class.php

Documentation is available at Sitemap.class.php

  1. <?php
  2.  
  3. /**
  4.  * Содержит класс Sitemap
  5.  *
  6.  * @package energine
  7.  * @subpackage core
  8.  * @author dr.Pavka
  9.  * @copyright Energine 2006
  10.  * @version $Id$
  11.  */
  12.  
  13. //require_once('core/framework/DBWorker.class.php');
  14. //require_once('core/framework/TreeConverter.class.php');
  15.  
  16.  
  17. /**
  18.  * Класс - синглтон
  19.  * Содержит методы по работе со структурой сайта
  20.  *
  21.  * @todo проблема с конечными страницами
  22.  *
  23.  * @package energine
  24.  * @subpackage core
  25.  * @author dr.Pavka
  26.  * @final
  27.  */
  28. final class Sitemap extends DBWorker {
  29.     /**
  30.      * @var TreeNodeList Экземпляр класса реализующего работу с древовидными структурами
  31.      * @access private
  32.      */
  33.     private $tree;
  34.  
  35.     /**
  36.      * @var Sitemap Instance объекта Sitema
  37.      * @access private
  38.      * @static
  39.      */
  40.     private static $instance;
  41.  
  42.     /**
  43.      * Информация о тех разделах, на которіе у юзера есть права
  44.      * @var array 
  45.      * @access private
  46.      */
  47.     private $info = array();
  48.  
  49.     /**
  50.      * Информация обо всех разделах(включая те на которые у текущего юзера нет прав)
  51.      *
  52.      * @var array 
  53.      * @access private
  54.      */
  55.     private $allInfo = array();
  56.  
  57.     /**
  58.      * Идентификатор дефолтной страницы
  59.      * Вынесено в переменную чтоб не дергать запрос постоянно
  60.      *
  61.      * @var int 
  62.      * @access private
  63.      */
  64.     private $defaultID = false;
  65.  
  66.     /**
  67.      * Дефолтные meta keywords
  68.      * Используется для всех страниц у которых не указано
  69.      * Вынесено в отдельную переменную, чтобы не дергать каждый раз запрос
  70.      *
  71.      * @var string 
  72.      * @access private
  73.      */
  74.     private $defaultMetaKeywords;
  75.  
  76.     /**
  77.      * Дефолтное meta description
  78.      *
  79.      * @var string 
  80.      * @access private
  81.      * @see Sitemap::defaultMetaKeywords
  82.      */
  83.     private $defaultMetaDescription;
  84.  
  85.     /**
  86.      * Идентификатор текущего языка
  87.      *
  88.      * @var int 
  89.      * @access private
  90.      */
  91.     private $langID;
  92.  
  93.     /**
  94.      * Кеширование уровней доступа
  95.      *
  96.      * @var array 
  97.      * @access private
  98.      */
  99.     private $cacheAccessLevels = array();
  100.  
  101.  
  102.     /**
  103.      * Конструктор класса
  104.      *
  105.      * @return void 
  106.      */
  107.     public function __construct({
  108.         //$this->startTimer();
  109.         parent::__construct();
  110.         $this->langID = Language::getInstance()->getCurrent();
  111.         $userGroups array_keys(UserGroup::getInstance()->asArray());
  112.  
  113.         //Кешируем уровни доступа к страницам сайта
  114.         //Формируем матрицу вида
  115.         //[идентификатор раздела][идентификатор роли] = идентификатор уровня доступа
  116.         foreach ($this->dbh->select('share_access_level'as $data{
  117.             foreach ($userGroups as $groupID{
  118.                 //todo проверить вариант с пересечением array_diff
  119.                 if (!isset($this->cacheAccessLevels[$data['smap_id']][$groupID]))
  120.                 $this->cacheAccessLevels[$data['smap_id']][$groupIDACCESS_NONE;
  121.             }
  122.             $this->cacheAccessLevels[$data['smap_id']][$data['group_id']] = (int)$data['right_id'];
  123.         }
  124.  
  125.         //Загружаем идентификаторы для последующего формирования древовидной стркутуры
  126.         //Получаем только идентификаторы разделов
  127.  
  128.         $res $this->dbh->selectRequest(
  129.             'SELECT s.smap_id, s.smap_pid FROM share_sitemap s '.
  130.             'LEFT JOIN share_sitemap_translation st ON st.smap_id = s.smap_id '.
  131.             'WHERE st.smap_is_disabled = 0 AND st.lang_id = %s '
  132.             'ORDER BY smap_order_num'
  133.         $this->langID);
  134.         if ($res === true{
  135.             throw new SystemException('ERR_NO_TRANSLATION'SystemException::ERR_CRITICAL);
  136.         }
  137.  
  138.  
  139.         //inspect($this->resetTimer());
  140.         //Фильтруем перечень идентификаторов отсекая те разделы на которые нет прав
  141.         $res array_filter($resarray($this'checkPageRights'));
  142.         //inspect($this->resetTimer());
  143.         //Загружаем перечень идентификаторов в объект дерева
  144.         $this->tree = TreeConverter::convert($res'smap_id''smap_pid');
  145.         //inspect($this->resetTimer());
  146.         //Получаем дефолтные meta заголовки
  147.         $res $this->dbh->select('share_sitemap_translation'array('smap_meta_keywords''smap_meta_description')array('smap_id' => $this->getDefault()'lang_id' => $this->langID));
  148.         list($res$res;
  149.         $this->defaultMetaKeywords = $res['smap_meta_keywords'];
  150.         $this->defaultMetaDescription = $res['smap_meta_description'];
  151.         $this->getSitemapData(array_keys($this->tree->asList()));
  152.  
  153.     }
  154.  
  155.     /**
  156.      * Возвращает экземпляр  объекта Sitemap
  157.      *
  158.      * @access public
  159.      * @return Sitemap 
  160.      * @static
  161.      */
  162.     public static function getInstance({
  163.         if (!isset(self::$instance)) {
  164.             self::$instance new Sitemap();
  165.         }
  166.         return self::$instance;
  167.     }
  168.  
  169.     /**
  170.      * Метод возвращающий информацию о разделах
  171.      *
  172.      * @param mixed идентификатор раздела или массив идентификаторов
  173.      * @return array 
  174.      * @access private
  175.      */
  176.  
  177.     private function getSitemapData($id{
  178.         if (!is_array($id)) {
  179.             $id array($id);
  180.         }
  181.         $diff array();
  182.  
  183.         if($diff array_diff($idarray_keys($this->info))){
  184.             $ids implode(','$diff);
  185.             $result convertDBResult(
  186.             $this->dbh->selectRequest(
  187.                     'SELECT s.smap_id, s.smap_pid, s.tmpl_id as templateID, s.smap_segment as Segment, s.smap_is_final as isFinal, st.smap_name, smap_redirect_url, smap_description_rtf, smap_html_title, smap_meta_keywords, smap_meta_description '.
  188.                     'FROM share_sitemap s '.
  189.                     'LEFT JOIN share_sitemap_translation st ON s.smap_id = st.smap_id '.
  190.                     'WHERE st.lang_id = '.$this->langID.' AND s.smap_id IN ('.$ids.')'),
  191.                 'smap_id'true);
  192.             $result array_map(array($this'preparePageInfo')$result);
  193.             $this->info += $result;
  194.         }
  195.         else{
  196.             $result array();
  197.             foreach ($this->info as $key=>$value){
  198.                 if(in_array($key$diff))
  199.                 $result[$key$value;
  200.             }
  201.         }
  202.  
  203.         return $result;
  204.     }
  205.  
  206.  
  207.     /**
  208.      * Внутренний метод по преобразования информации о документе. Сводит все ключи к camel notation и для линка изменяет значение идентификатора шаблона
  209.      *
  210.      * @param array 
  211.      * @return array 
  212.      * @access private
  213.      */
  214.  
  215.     private function preparePageInfo($current{
  216.         $result convertFieldNames($current,'smap');
  217.         if(is_null($result['MetaKeywords'])) $result['MetaKeywords'$this->defaultMetaKeywords;
  218.         if(is_null($result['MetaDescription'])) $result['MetaDescription'$this->defaultMetaDescription;
  219.         if($result['RedirectUrl']$result['RedirectUrl'(URI::validate($result['RedirectUrl']))?$result['RedirectUrl']:Request::getInstance()->getBasePath().$result['RedirectUrl'];
  220.  
  221.         return $result;
  222.     }
  223.  
  224.  
  225.     /**
  226.      * Возвращает идентификатор страницы по умолчанию
  227.      *
  228.      * @return int 
  229.      * @access public
  230.      */
  231.  
  232.     public function getDefault({
  233.         if (!$this->defaultID{
  234.             $result simplifyDBResult($this->dbh->select('share_sitemap''smap_id'array('smap_default' => true))'smap_id'true);
  235.             if ($result === false{
  236.                 throw new SystemException('ERR_DEV_NO_DEFAULT_PAGE'SystemException::ERR_CRITICAL);
  237.             }
  238.  
  239.             $this->defaultID = $result;
  240.         }
  241.         return $this->defaultID;
  242.     }
  243.  
  244.     /**
  245.      * Возвращает часть строки УРЛ по идентификатор
  246.      *
  247.      * @todo Ошибка с вычислением URL для конечных разделов
  248.      *
  249.      * @param int 
  250.      * @return string 
  251.      * @access public
  252.      */
  253.  
  254.     public function getURLByID($smapID{
  255.         $result array();
  256.         $node $this->tree->getNodeById($smapID);
  257.         if (!is_null($node)) {
  258.             $parents array_reverse(array_keys($node->getParents()->asList(false)));
  259.             foreach ($parents as $id{
  260.                 if (isset($this->info[$id])) {
  261.                     $result[$this->info[$id]['Segment'];
  262.                 }
  263.                 else {
  264.                     $res $this->getDocumentInfo($idfalse);
  265.                     $result[$res['Segment'];
  266.                 }
  267.             }
  268.         }
  269.  
  270.         $currentSegment $this->getDocumentInfo($smapID);
  271.         $currentSegment $currentSegment['Segment'];
  272.         $result[$currentSegment;
  273.         $result implode('/'$result).'/';
  274.         return $result;
  275.     }
  276.  
  277.     /**
  278.      * Возвращает идентификатор страницы по его URL
  279.      *
  280.      * @param array 
  281.      * @return int 
  282.      * @access public
  283.      */
  284.  
  285.     public function getIDByURI(array $segments$useDefaultIfEmpty false{
  286.         $id null;
  287.         $i 1;
  288.         $request Request::getInstance();
  289.  
  290.         if (empty($segments&& $useDefaultIfEmpty{
  291.             return $this->getDefault();
  292.         }
  293.  
  294.         foreach ($segments as $segment{
  295.             $res $this->dbh->select('share_sitemap'array('smap_id')array('smap_segment' => $segment'smap_pid' => $id));
  296.             if (!is_array($res)) {
  297.                 break;
  298.             }
  299.             /**
  300.              * @todo Тут вот херня
  301.              */
  302.             $request->setPathOffset($i);
  303.             list($res$res;
  304.             $id $res['smap_id'];
  305.             $i++;
  306.         }
  307.  
  308.         return $id;
  309.     }
  310.  
  311.     /**
  312.      * Определение прав набора групп на страницу
  313.      *
  314.      * @param int идентификатор документа
  315.      * @param mixed группа/набор групп, если не указан, берется группа/группы текущего пользовател
  316.      * @return int 
  317.      * @access public
  318.      */
  319.     public function getDocumentRights($docID$groups false{
  320.         if (!$groups{
  321.             $groups AuthUser::getInstance()->getGroups();
  322.         }
  323.         elseif (!is_array($groups)) {
  324.             $groups array($groups);
  325.         }
  326.  
  327.         $groups array_combine($groups$groups);
  328.  
  329.         return max(array_intersect_key($this->cacheAccessLevels[$docID]$groups));
  330.     }
  331.  
  332.     /**
  333.      * Возвращает меню первого уровн
  334.      *
  335.      * @return array 
  336.      * @access public
  337.      */
  338.  
  339.     public function getMainLevel({
  340.         return $this->buildPagesMap(array_keys($this->tree->asList(false)));
  341.     }
  342.  
  343.  
  344.     /**
  345.      * Возвращает все дочерние разделы
  346.      *
  347.      * @param int идентификатор раздела
  348.      * @return array 
  349.      * @access public
  350.      */
  351.  
  352.     public function getChilds($smapID{
  353.         $result array();
  354.         if ($node $this->tree->getNodeById($smapID)) {
  355.             $result $this->buildPagesMap(array_keys($node->getChildren()->asList(false)));
  356.         }
  357.         return $result;
  358.     }
  359.  
  360.     /**
  361.      * Возвращает родителя
  362.      *
  363.      * @return int 
  364.      * @access public
  365.      */
  366.  
  367.     public function getParent($smapID{
  368.         $node $this->tree->getNodeById($smapID);
  369.         $result false;
  370.         if (!is_null($node)) {
  371.             $result key($node->getParents()->asList(false));
  372.         }
  373.  
  374.         return $result;
  375.     }
  376.  
  377.     /**
  378.      * Возвращает массив родителей
  379.      *
  380.      * @param int Идентфикатор раздела
  381.      * @return array 
  382.      * @access public
  383.      */
  384.  
  385.     public function getParents($smapID{
  386.         $node $this->tree->getNodeById($smapID);
  387.         $result array();
  388.         if (!is_null($node)) {
  389.             $result $this->buildPagesMap(array_reverse(array_keys($node->getParents()->asList(false))));
  390.         }
  391.         return $result;
  392.     }
  393.  
  394.     /**
  395.      * По переданному массиву идентификаторов разделов и массиву перечня полей формирует  cтруктуру array('$идентификатор_раздела'=>array())
  396.      *
  397.      * @param array идентификаторы разделов
  398.      * @return array 
  399.      * @access private
  400.      */
  401.  
  402.     private function buildPagesMap($ids{
  403.         $result array();
  404.         if (is_array($ids)) {
  405.             foreach ($ids as $id{
  406.                 $info $this->getDocumentInfo($id);
  407.                 $info['Segment'$this->getURLByID($id);
  408.                 $result[$id$info;
  409.             }
  410.         }
  411.  
  412.         return $result;
  413.     }
  414.  
  415.     /**
  416.      * Возвращает информацию о документе
  417.      * Ищем документ с нужным идентификатором в $this->info
  418.      *
  419.      * @param int Идентификатор раздела
  420.      * @return array 
  421.      * @access public
  422.      */
  423.  
  424.     public function getDocumentInfo($id{
  425.         if(isset($this->info[$id]))
  426.           $result $this->info[$id];
  427.         else{
  428.             $result $this->getSitemapData($id);
  429.             $result $result[$id];
  430.         }  
  431.         return $result;
  432.     }
  433.  
  434.  
  435.     /**
  436.      * Возвращает объект Tree
  437.      *
  438.      * @return TreeNodeList 
  439.      * @access public
  440.      */
  441.  
  442.     public function getTree({
  443.         return $this->tree;
  444.     }
  445.  
  446.     /**
  447.      * Возвращает всю информацию о раздеах в не структурированном виде
  448.      *
  449.      * @return array 
  450.      * @access public
  451.      */
  452.  
  453.     public function getInfo({
  454.         return $this->info;
  455.     }
  456.  
  457.     /**
  458.      * Внутренний метод для фильтрации разделов, на которые нет прав
  459.      * Вызывется как callback для array_filter
  460.      *
  461.      * @param array 
  462.      * @return boolean 
  463.      * @access private
  464.      */
  465.  
  466.     private function checkPageRights($smapInfo{
  467.         return ($this->getDocumentRights($smapInfo['smap_id']!= ACCESS_NONE);
  468.     }
  469. }
В создании документации нам помог: phpDocumentor