Файл: DESURE-dcms-f12de01ac63e/sys/plugins/classes/menu.class.php
Строк: 171
<?php
class menu
{
protected
$_require_keys = array(
'id',
'id_parent',
'position',
'title',
'url'
);
protected
$_menu_key,
$_items,
$_last_item_id = 0;
function __construct($key_or_items = null)
{
if (is_array($key_or_items)) {
$this->_items = $this->_parseItems($key_or_items);
$this->_menu_key = $this->_parseKeyFromItems($this->_items);
} elseif (is_scalar($key_or_items)) {
$items = $this->_getItemsFromBase($key_or_items);
$this->_items = $this->_parseItems($items);
$this->_menu_key = $key_or_items;
} else {
$this->_items = array();
$this->_menu_key = null;
}
}
private function _parseItems($its)
{
$items = array();
foreach ($its as $item) {
foreach ($this->_require_keys as $require_key) {
if (!array_key_exists($require_key, $item)) {
throw new Exception(__('У элемента отсутствует параметр %s', $require_key));
}
}
if (!is_numeric($item['id'])) {
throw new Exception(__('Параметр %s должен быть %s', 'id', 'integer'));
}
$items[] = $item;
$this->_last_item_id = max($this->_last_item_id, $item['id']);
}
return $items;
}
private function _parseKeyFromItems($items)
{
foreach ($items AS $item) {
if (array_key_exists('menu_key', $item)) {
return $item['menu_key'];
}
}
return null;
}
private function _getItemsFromBase($menu_key)
{
$db = db::me();
$res = $db->prepare("SELECT * FROM `menu` WHERE `menu_key` = :menu_key");
$res->execute(array(':menu_key' => $menu_key));
return $res->fetchAll();
}
private function _setItemId($old_id, $now_id)
{
foreach ($this->_items AS $index => $item) {
if ($item['id'] === $old_id) {
$this->_items[$index]['id'] = $now_id;
}
if ($item['id_parent'] === $old_id) {
$this->_items[$index]['id_parent'] = $now_id;
}
}
}
private function _saveByParent($id_parent = null, $level = 0)
{
if ($level > 10) {
throw new Exception(__("Слишком большая вложенность меню"));
}
$items = $this->getItems($id_parent);
$db = db::me();
$res = $db->prepare("INSERT INTO `menu` (`menu_key`, `id_parent`, `position`, `title`, `url`, `data`) VALUES (:menu_key, :id_parent, :position, :title, :url, :dt)");
$position = 0;
foreach ($items AS $item) {
$res->execute(array(
':menu_key' => $this->_menu_key,
':id_parent' => $id_parent,
':position' => ++$position,
':title' => $item['title'],
':url' => $item['url'],
':dt' => array_key_exists('data', $item) ? $item['data'] : null
));
$id = $db->lastInsertId();
$this->_setItemId($item['id'], $id);
$this->setItemPosition($id, $position);
$this->_saveByParent($id, $level + 1);
}
}
/**
* @return null|string
*/
public function getMenuKey()
{
return $this->_menu_key;
}
private function _position_cmp($item1, $item2)
{
$a = $item1['position'];
$b = $item2['position'];
switch (true) {
case $a == $b:
return 0;
case $a > $b:
return 1;
case $a < $b:
return -1;
}
}
/**
* Сохранение меню в базе
* @param string $key Ключ меню (можно не указывать, если меню инициализировано по ключу)
* @throws Exception
*/
public function save($key = null)
{
if (!$key && !$this->_menu_key) {
throw new Exception(__('Ключ меню не задан'));
}
if ($this->_menu_key) {
$db = db::me();
$res = $db->prepare("DELETE FROM `menu` WHERE `menu_key` = :menu_key");
$res->execute(array(':menu_key' => $this->_menu_key));
}
if ($key && is_scalar($key)) {
$this->_menu_key = $key;
}
$this->_saveByParent(null); // рекурсивное сохранение от корня
}
/**
* Добавление пункта меню
* @param string $url Ссылка
* @param string $title Заголовок
* @param int $position Позиция на уровне
* @param int|null $id_parent Родитель (null-корень)
* @return int Идентификатор нового пункта
* @throws Exception
*/
public function addItem($title, $url, $position = 0, $id_parent = null)
{
if (!is_null($id_parent) && !$this->getItemById($id_parent)) {
throw new Exception(__("Родитель с id %s не найден", $id_parent));
}
$id = ++$this->_last_item_id;
$this->_items[] = array(
'id' => $id,
'menu_key' => $this->_menu_key,
'id_parent' => $id_parent,
'position' => $position,
'title' => $title,
'url' => $url
);
return $id;
}
/**
* Установка позиции пункта меню
* @param int $id Идентификатор
* @param int $position позиция на уровне
*/
public function setItemPosition($id, $position)
{
foreach ($this->_items AS $key => $item) {
if ($item['id'] === $id) {
$this->_items[$key]['position'] = $position;
}
}
}
/**
* Удаление пункта меню со всеми дочерними пунктами
* @param int $id
*/
public function removeItemById($id)
{
$child_items = $this->getItems($id);
foreach ($child_items as $item) {
$this->removeItemById($item['id']);
}
foreach ($this->_items as $key => $item) {
if ($item['id'] === $id) {
unset($this->_items[$key]);
}
}
$this->_items = array_values($this->_items); // сбрасываем ключи элементов.
}
/**
* Получение пункта меню по его идентификатору
* @param int $id Идентификатор
* @return array|null
*/
public function getItemById($id)
{
foreach ($this->_items as $item) {
if ($item['id'] === $id) {
return $item;
}
}
return null;
}
/**
* Получение списка пунктов меню
* @param int|null $id_parent Родитель (null - корневые элементы)
* @param bool $recursive Рекурсивное получение всех дочерних пунктов меню
* @return array
*/
public function getItems($id_parent = null, $recursive = false)
{
$items = array();
foreach ($this->_items AS $item) {
if ($item['id_parent'] === $id_parent) {
$it = $item;
if ($recursive) {
$it['items'] = $this->getItems($it['id'], true);
}
$items[] = $it;
}
}
usort($items, array($this, '_position_cmp'));
return $items;
}
}