Location: PHPKode > projects > Energine > energine-2.2/core2a/framework/Sitemap.class.php
<?php

/**
 * Содержит класс Sitemap
 *
 * @package energine
 * @subpackage core
 * @author dr.Pavka
 * @copyright ColoCall 2006
 * @version $Id: Sitemap.class.php,v 1.14 2007/12/17 14:16:03 pavka Exp $
 */

//require_once('core/framework/DBWorker.class.php');
//require_once('core/framework/TreeConverter.class.php');


/**
 * Класс - синглтон
 * Содержит методы по работе со структурой сайта
 *
 * @package energine
 * @subpackage core
 * @final
 */
final class Sitemap extends DBWorker {
    /**
     * @var TreeNodeList Экземпляр класса реализующего работу с древовидными структурами
     * @access private
     */
    private $tree;

    /**
     * @var Sitemap Instance объекта Sitemap
     * @access private
     * @static
     */
    private static $instance;

    /**
     * Информация о тех разделах, на которіе у юзера есть права
     * @var array
     * @access private
     */
    private $info = array();

    /**
     * Информация обо всех разделах(включая те на которые у текущего юзера нет прав)
     *
     * @var array
     * @access private
     */
    private $allInfo = array();

    /**
     * Идентификатор дефолтной страницы
     * Вынесено в переменную чтоб не дергать запрос постоянно
     *
     * @var int
     * @access private
     */
    private $defaultID = false;

    /**
     * Дефолтные meta keywords
     * Используется для всех страниц у которых не указано
     * Вынесено в отдельную переменную, чтобы не дергать каждый раз запрос
     *
     * @var string
     * @access private
     */
    private $defaultMetaKeywords;

    /**
     * Дефолтное meta description
     *
     * @var string
     * @access private
     * @see Sitemap::defaultMetaKeywords
     */
    private $defaultMetaDescription;

    /**
     * Идентификатор текущего языка
     *
     * @var int
     * @access private
     */
    private $langID;


    /**
     * Конструктор класса
     *
     * @return void
     */
    public function __construct() {
        parent::__construct();
        $this->langID = Language::getInstance()->getCurrent();
        //Загружаем идентификаторы для последующего формирования древовидной стркутуры
        //Получаем только идентификаторы разделов

        $res = $this->dbh->selectRequest('
            SELECT s.smap_id, s.smap_pid FROM share_sitemap s
            LEFT JOIN share_sitemap_translation st ON st.smap_id = s.smap_id
            WHERE st.smap_is_disabled = 0 AND st.lang_id = %s AND smap_is_final = 0
            ORDER BY smap_order_num
        ', $this->langID);
        if ($res === true) {
            throw new SystemException('ERR_NO_TRANSLATION', SystemException::ERR_CRITICAL);
        }

        //Фильтруем перечень идентификаторов отсекая те разделы на которые нет прав
        $res = array_filter($res, array($this, 'checkPageRights'));

        //Загружаем перечень идентификаторов в объект дерева
        $this->tree = TreeConverter::convert($res, 'smap_id', 'smap_pid');

        //Получаем дефолтные meta заголовки
        $res = $this->dbh->select('share_sitemap_translation', array('smap_meta_keywords', 'smap_meta_description'), array('smap_id' => $this->getDefault(), 'lang_id' => $this->langID));
        list($res) = $res;
        $this->defaultMetaKeywords = $res['smap_meta_keywords'];
        $this->defaultMetaDescription = $res['smap_meta_description'];
        $this->info = $this->getSitemapData(array_keys($this->tree->asList()));
    }

    /**
     * Возвращает экземпляр  объекта Sitemap
     *
     * @access public
     * @return Sitemap
     * @static
     */
    public static function getInstance() {
        if (!isset(self::$instance)) {
            self::$instance = new Sitemap();
        }
        return self::$instance;
    }

    /**
     * Метод возвращающий информацию о разделах
     *
     * @param mixed идентификатор раздела или массив идентификаторов
     * @return array
     * @access private
     */

    private function getSitemapData($id) {
        if (!is_array($id)) {
        	$id = array($id);
        }

        $ids = implode(',', $id);

        $result = convertDBResult(
            $this->dbh->selectRequest(
                '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_description_rtf, smap_html_title, smap_meta_keywords, smap_meta_description '.
                'FROM share_sitemap s '.
                'LEFT JOIN share_sitemap_translation st ON s.smap_id = st.smap_id '.
                'WHERE st.lang_id = '.$this->langID.' AND s.smap_id IN ('.$ids.')'),
            'smap_id', true);
        $result = array_map(array($this, 'preparePageInfo'), $result);
        return $result;
    }


    /**
     * Внутренний метод по преобразования информации о документе. Сводит все ключи к camel notation и для линка изменяет значение идентификатора шаблона
     *
     * @param array
     * @return array
     * @access private
     */

    private function preparePageInfo($current) {
        $result = convertFieldNames($current,'smap');
        if(is_null($result['MetaKeywords'])) $result['MetaKeywords'] = $this->defaultMetaKeywords;
        if(is_null($result['MetaDescription'])) $result['MetaDescription'] = $this->defaultMetaDescription;
        return $result;
    }


    /**
     * Возвращает идентификатор страницы по умолчанию
     *
     * @return int
     * @access public
     */

    public function getDefault() {
        if (!$this->defaultID) {
            $result = simplifyDBResult($this->dbh->select('share_sitemap', 'smap_id', array('smap_default' => true)), 'smap_id', true);
            if ($result === false) {
                throw new SystemException('ERR_DEV_NO_DEFAULT_PAGE', SystemException::ERR_CRITICAL);
            }

            $this->defaultID = $result;
        }
        return $this->defaultID;
    }

    /**
     * Возвращает часть строки УРЛ по идентификатору
     *
     * @param int
     * @return string
     * @access public
     */

    public function getURLByID($smapID) {
        $result = array();
        $node = $this->tree->getNodeById($smapID);
        if (!is_null($node)) {
            $parents = array_reverse(array_keys($node->getParents()->asList(false)));
            foreach ($parents as $id) {
                if (isset($this->info[$id])) {
                    $result[] = $this->info[$id]['Segment'];
                }
                else {
                	$res = $this->getDocumentInfo($id, false);
                	$result[] = $res['Segment'];
                }
            }
        }

        $currentSegment = $this->getDocumentInfo($smapID);
        $currentSegment = $currentSegment['Segment'];
        $result[] = $currentSegment;
        $result = implode('/', $result).'/';
        return $result;
    }

    /**
     * Возвращает идентификатор страницы по его URL
     *
     * @param array
     * @return int
     * @access public
     */

    public function getIDByURI(array $segments, $useDefaultIfEmpty = false) {
        $id = null;
        $i = 1;
        $request = Request::getInstance();

        if (empty($segments) && $useDefaultIfEmpty) {
            return $this->getDefault();
        }

        foreach ($segments as $segment) {
            $res = $this->dbh->select('share_sitemap', array('smap_id'), array('smap_segment' => $segment, 'smap_pid' => $id));
            if (!is_array($res)) {
                break;
            }

            $request->setPathOffset($i);
            list($res) = $res;
            $id = $res['smap_id'];
            $i++;
        }

        return $id;
    }

    /**
     * Определение прав набора групп на страницу
     *
     * @param int идентификатор документа
     * @param mixed группа/набор групп, если не указан, берется группа/группы текущего пользователя
     * @return int
     * @access public
     */
    public function getDocumentRights($docID, $groups = false) {
        if (!$groups) {
            $user = AuthUser::getInstance();
            $groups = $user->getGroups();
        }
        elseif (!is_array($groups)) {
            $groups = array($groups);
        }

        $result = array(ACCESS_NONE);

        foreach ($groups as $groupID) {
            //для каждой группы определяем уровень прав
            $res = $this->dbh->select('share_access_level', 'right_id', array('smap_id' => $docID, 'group_id' => $groupID));
            if (is_array($res)) {
                $result[] = simplifyDBResult($res, 'right_id', true);
            }
        }

        return max($result);
    }

    /**
     * Возвращает меню первого уровня
     *
     * @return array
     * @access public
     */

    public function getMainLevel() {
        return $this->buildPagesMap(array_keys($this->tree->asList(false)));
    }


    /**
     * Возвращает все дочерние разделы
     *
     * @param int идентификатор раздела
     * @return array
     * @access public
     */

    public function getChilds($smapID) {
        $result = array();
        if ($node = $this->tree->getNodeById($smapID)) {
            $result = $this->buildPagesMap(array_keys($node->getChildren()->asList(false)));
        }
        return $result;
    }

    /**
     * Возвращает массив родителей
     *
     * @param int Идентфикатор раздела
     * @return array
     * @access public
     */

    public function getParents($smapID) {
        $node = $this->tree->getNodeById($smapID);
        $result = array();
        if (!is_null($node)) {
        	$result = $this->buildPagesMap(array_reverse(array_keys($node->getParents()->asList(false))));
        }
        return $result;
    }

    /**
     * По переданному массиву идентификаторов разделов и массиву перечня полей формирует  cтруктуру array('$идентификатор_раздела'=>array())
     *
     * @param array идентификаторы разделов
     * @return array
     * @access private
     */

    private function buildPagesMap($ids) {
        $result = array();
        if (is_array($ids)) {
        	foreach ($ids as $id) {
        		$info = $this->getDocumentInfo($id);
        		$info['Segment'] = $this->getURLByID($id);
        		$result[$id] = $info;
        	}
        }

        return $result;
    }

    /**
     * Возвращает информацию о документе
     * Сначала ищем есть ли документ с нужным идентификатором в $this->info
     * Если его там нет, получаем инфу о нем и добавляем в $this->info
     *
     * @param int Идентификатор раздела
     * @param кешировать ли информацию о странице в $this->info
     * @return array
     * @access public
     */

    public function getDocumentInfo($id, $cache = true) {
        if (!isset($this->info[$id])) {
            $result = $this->getSitemapData($id);
            if ($cache) {
                $this->info = $this->info + $result;
            }
            $result = $result[$id];
        }
        else {
        	$result = $this->info[$id];
        }

        return $result;
    }


    /**
     * Возвращает объект Tree
     *
     * @return TreeNodeList
     * @access public
     */

    public function getTree() {
        return $this->tree;
    }

    /**
     * Возвращает всю информацию о раздеах в не структурированном виде
     *
     * @return array
     * @access public
     */

    public function getInfo() {
        return $this->info;
    }

    /**
     * Внутренний метод для фильтрации разделов, на которые нет прав
     * Вызывется как callback для array_filter
     *
     * @param array
     * @return boolean
     * @access private
     */

    private function checkPageRights($smapInfo) {
        return ($this->getDocumentRights($smapInfo['smap_id']) != ACCESS_NONE);
    }
}

Return current item: Energine