TYPE_STR, # Название 'mtitle' => TYPE_STR, # Meta title 'mkeywords' => TYPE_STR, # Meta keywords 'mdescription' => TYPE_STR, # Meta description ]; public function init() { parent::init(); $this->tree = new NestedSetsTree(static::TABLE_SITEMAP); $this->tree->init(); } /** * Item model * @param integer|null $id * @param array $columns * @param array $with * @param string|null $lang * @return \bff\modules\sitemap\models\Item | \bff\db\illuminate\Model |array */ public function item($id = null, $columns = ['*'], array $with = [], $lang = null) { $model = $this->model('Item'); if (! empty($id)) { return $model->one($id, $columns, $with, $lang); } return $model; } /** * Создаем раздел * @param int $parentItemID @ref ID parent-раздела * @param array $parentData данные о parent-разделе * @param array $data данные * @return int ID созданного раздела или 0 */ public function itemCreate(&$parentItemID, array $parentData, array $data) { $data['created'] = $this->db->now(); $itemID = $this->tree->insertNode($parentItemID); if (empty($itemID)) { return 0; } $this->db->update(static::TABLE_SITEMAP, array_diff_key($data, $this->langItems), [ 'id' => $itemID, ]); $data['id'] = $itemID; if ($parentData['numlevel'] > 1) { $mainParentID = $this->tree->getNodeParentsID($parentItemID, ' AND numlevel = 1 '); if (!empty($mainParentID)) { reset($mainParentID); $parentItemID = current($mainParentID); } } $this->db->langInsert($itemID, $data, $this->langItems, static::TABLE_SITEMAP_LANG); return $itemID; } /** * Обновляем данные о разделе * @param int $itemID ID раздела * @param array $data данные * @return bool */ public function itemUpdate($itemID, array $data) { if (empty($itemID) || empty($data)) { return false; } $res = $this->db->update(static::TABLE_SITEMAP, array_diff_key($data, $this->langItems), [ 'id' => $itemID, ]); $this->db->langUpdate($itemID, $data, $this->langItems, static::TABLE_SITEMAP_LANG); return !empty($res); } /** * Удаляем раздел * @param int $itemID ID раздела * @return bool */ public function itemDelete($itemID) { $data = $this->db->select_row(static::TABLE_SITEMAP, ['*'], ['id' => $itemID]); if (empty($data)) { return false; } if ($data['is_system'] && ! $this->isAdminFordev()) { $this->errors->accessDenied(); return false; } $deleteItemsID = $this->tree->deleteNode($itemID); if (!$deleteItemsID) { return false; } else { $this->db->delete(static::TABLE_SITEMAP_LANG, $itemID); return true; } } /** * Получаем данные о разделе * @param int $itemID ID раздела * @param bool $edit * @return array */ public function itemData($itemID, $edit = false) { if ($edit) { $data = $this->db->select_row(static::TABLE_SITEMAP, ['*'], ['id' => $itemID]); if (!empty($data)) { $this->db->langSelect($itemID, $data, $this->langItems, static::TABLE_SITEMAP_LANG); } } else { $data = $this->db->one_array( 'SELECT I.*, L.* FROM ' . static::TABLE_SITEMAP . ' I, ' . static::TABLE_SITEMAP_LANG . ' L WHERE I.id = :id ' . ( ! $this->isAdminFordev() ? ' AND I.pid!=0 ' : '') . $this->db->langAnd(), [':id' => $itemID] ); } return $data; } /** * Получаем данные о разделе по фильтру * @param array $filter фильтр раздела * @return array */ public function itemDataByFilter(array $filter = []) { $filter[':lang'] = $this->db->langAnd(false); $filter = $this->prepareFilter($filter, 'I'); return $this->db->one_array('SELECT I.*, L.* FROM ' . static::TABLE_SITEMAP . ' I, ' . static::TABLE_SITEMAP_LANG . ' L ' . $filter['where'] . ' ORDER BY I.id ASC LIMIT 1', $filter['bind']); } /** * Перемещаем разделы */ public function itemsRotate() { return $this->tree->rotateTablednd(); } /** * Включаем/вылючаем раздел * @param int $itemID ID раздела */ public function itemToggle($itemID) { $this->tree->toggleNodeEnabled($itemID, true, false); } /** * Получаем список разделов по фильтру * @param array $filter фильтр * @param array $fields поля * @param string $orderBy * @param string $limit * @return array|integer */ public function itemsByFilter(array $filter = [], $fields = [], $orderBy = 'numleft', $limit = '') { $from = ' FROM ' . static::TABLE_SITEMAP . ' I, ' . static::TABLE_SITEMAP_LANG . ' L '; $filter[':lang'] = $this->db->langAnd(false); $filter = $this->prepareFilter($filter, 'I'); if (empty($fields)) { return (int)$this->db->one_data('SELECT COUNT(*) AS cnt ' . $from . $filter['where'], $filter['bind']); } foreach ($fields as & $v) { if (strpos($v, '.') === false) { $v = array_key_exists($v, $this->langItems) ? 'L.' . $v : 'I.' . $v; } } unset($v); return $this->db->select('SELECT ' . join(',', $fields) . $from . $filter['where'] . ($orderBy ? ' ORDER BY ' . $orderBy . ' ' : ' ') . $limit, $filter['bind']); } /** * Получаем список разделов в заданной ветке * @param int $numleft numleft * @param int $numright numright * @return mixed */ public function itemsListing($numleft, $numright) { return $this->db->select( 'SELECT I.*, L.title, (I.type = :type) as menu FROM ' . static::TABLE_SITEMAP . ' I, ' . static::TABLE_SITEMAP_LANG . ' L WHERE I.pid != 0 AND I.numleft > :nl AND I.numright < :nr ' . $this->db->langAnd() . ' ORDER BY I.numleft', [':type' => static::typeMenu, ':nl' => $numleft, ':nr' => $numright] ); } /** * Получаем список меню для построения их в админ-панели * @return mixed */ public function itemsListingMenu() { return $this->db->select_key( 'SELECT I.id, L.title, I.numleft, I.numright, I.numlevel, 0 as active FROM ' . static::TABLE_SITEMAP . ' I, ' . static::TABLE_SITEMAP_LANG . ' L WHERE I.pid = :root AND I.type = :type ' . $this->db->langAnd() . ' ORDER BY I.numleft', 'id', [':root' => static::ROOT_ID, ':type' => static::typeMenu] ); } /** * Получаем список разделов для построения меню * @return mixed */ public function itemsMenu() { $menu = $this->db->select('SELECT I.id, I.pid, I.keyword, I.link, I.type, I.target, I.style, I.owned_by, L.title, L.mtitle, L.mkeywords, L.mdescription, 0 as a FROM ' . static::TABLE_SITEMAP . ' I, ' . static::TABLE_SITEMAP_LANG . ' L WHERE I.pid>=1 AND I.enabled = 1 ' . $this->db->langAnd() . ' ORDER BY I.numleft'); return $this->db->transformRowsToTree($menu, 'id', 'pid', 'sub'); } /** * Формируем список parent-элементов * @param int $selectedID ID текущего parent-раздела * @param int $numlevelMax масимальный уровень вложенности * @return string */ public function itemParentsOptions($selectedID, $numlevelMax = 3) { $parentOptions = ''; $items = $this->db->select('SELECT I.id, L.title, I.numlevel FROM ' . static::TABLE_SITEMAP . ' I, ' . static::TABLE_SITEMAP_LANG . ' L WHERE (I.type = ' . static::typeMenu . ' OR I.id = 1) AND I.numlevel < :nl ' . $this->db->langAnd() . ' ORDER BY I.numleft', [':nl' => $numlevelMax]); foreach ($items as $v) { $parentOptions .= ''; } return $parentOptions; } /** * Формируем путь parent-элементов для отображения * @param int $itemID ID раздела * @param string $separator * @param string|null $lang * @return string */ public function itemParentsPath($itemID, $separator = ' > ', $lang = null) { $lang = $lang ?? $this->locale->current(); $parentsID = $this->tree->getNodeParentsID($itemID, ($itemID == static::ROOT_ID ? '' : ' AND numlevel > 0'), true); if (empty($parentsID)) { return ''; } $parentTitle = $this->db->select_one_column('SELECT title FROM ' . static::TABLE_SITEMAP_LANG . ' WHERE id IN (' . join(',', $parentsID) . ') AND lang = :lng ORDER BY id', [':lng' => $lang]); return join($separator, $parentTitle); } /** * Выполняем очистку таблиц модуля, оставляем только корневой раздел * @param string $rootTitle название корневого раздела * @return bool|int */ public function itemsClear($rootTitle = '') { if (! $this->isAdminFordev()) { return false; } # чистим таблицы Sitemap $this->db->exec('TRUNCATE TABLE ' . static::TABLE_SITEMAP); $this->db->exec('TRUNCATE TABLE ' . static::TABLE_SITEMAP_LANG); # сбрасываем seq для postgres if ($this->db->isPgSQL()) { $this->db->pgRestartSequence(static::TABLE_SITEMAP); } # создаем корневой элемент $rootID = $this->db->insert(static::TABLE_SITEMAP, [ 'pid' => 0, 'keyword' => 'root', 'created' => $this->db->now(), 'is_system' => 1, 'numleft' => 1, 'numright' => 2, 'numlevel' => 0, 'enabled' => 1, 'allow_submenu' => 1, ]); if (empty($rootID)) { return false; } $this->input->postm_lang($this->langItems, $data); foreach ($this->locale->getLanguages() as $lng) { $data['title'][$lng] = (!empty($rootTitle) ? $rootTitle : _t('sitemap', 'Root Section')); } $this->db->langInsert($rootID, $data, $this->langItems, static::TABLE_SITEMAP_LANG); return $rootID; } public function getLocaleTables() { return [ static::TABLE_SITEMAP => ['type' => 'table', 'fields' => $this->langItems, 'title' => _t('sitemap', 'Sitemap')], ]; } }