array('redirectAlias')); protected $_fileFields = array('image'); public $itemName = 'Page'; public $itemsName = 'Pages'; public $idParent = 0; public static function getInstance() { if (null === self::$_instance) { self::$_instance = new self(); } return self::$_instance; } protected function _arrayParseTag2Url(&$array, $fields = null) { if (null === $fields) { $fields = $this->_urlParseFields; } if (empty($fields) || !is_array($array) || empty($array)) { return false; } foreach ($fields as $key => $field) { if (is_scalar($field)) { if (isset($array[$field])) { $array[$field] = $this->_tag2BaseUrl($array[$field]); } } else { if (isset($array[$key])) { $this->_arrayParseTag2Url($array[$key], $field); } } } return true; } protected function _arrayParseUrl2Tag(&$array, $fields = null) { if (null === $fields) { $fields = $this->_urlParseFields; } if (empty($fields) || !is_array($array) || empty($array)) { return false; } foreach ($fields as $key => $field) { if (is_scalar($field)) { if (isset($array[$field])) { $array[$field] = $this->_baseUrl2Tag($array[$field]); } } else { if (isset($array[$key])) { $this->_arrayParseUrl2Tag($array[$key], $field); } } } return true; } protected function _join(Zend_Db_Select $select = null) { $select = parent::_join($select); $select->join( array('cDef' => $this->_getTableName('PageContent')), "`cDef`.`idPage` = `{$this->_tableAlias}`.`id` " . "AND `cDef`.`language` = " . $this->db->quote(Qs_Db_Language::getDefault()), array( 'IFNULL(`c`.`title`, `cDef`.`title`) AS title', 'IFNULL(`c`.`menuTitle`, `cDef`.`menuTitle`) AS menuTitle', 'IFNULL(`c`.`header`, `cDef`.`header`) AS header' ) ); $select->joinLeft(array('c' => $this->_getTableName('PageContent')), "`c`.`idPage` = `{$this->_tableAlias}`.`id` " . "AND `c`.`language` = " . $this->db->quote($this->getLanguage()), null); $select->joinLeft( array('dp' => $this->_getTableName('DraftPage')), "`dp`.`id` = `{$this->_tableAlias}`.`id` ", array('hasDraft' => "IF(`dp`.`id` IS NOT NULL AND `dp`.`added` <> `dp`.`changed`, 'y', 'n')") ); // if (!empty($this->_filter)) { // $select->joinLeft( // array('pop' => $this->_getTableName('PageOption')), // "`pop`.`idPage` = `{$this->_tableAlias}`.`id` ", // null // ); // } return $select; } // protected function _group(Zend_Db_Select $select = null) // { // $select = parent::_group($select); // if (!empty($this->_filter)) { // $select->group('idPage'); // } // return $select; // } protected function _filterWhere(Zend_Db_Select $select) { if (!empty($this->_filterFields) && array_key_exists('query', $this->_filter)) { Qs_Db_Filter::where($select, $this->_filterFields, $this->_filter['query']); } foreach ($this->_filter as $field => $value) { if (empty($value)) { continue; } switch ($field) { case 'handler': $select->where("`{$this->_tableAlias}`.`{$field}` IN (" . $this->db->quote($value) . ')'); break; case 'system': $select->where("`{$this->_tableAlias}`.`system` = " . $this->db->quote($value)); break; case 'showInSiteMap': $select->where("`{$this->_tableAlias}`.`showInSiteMap` = " . $this->db->quote($value)); break; case 'showInMenu': $select->where("`{$this->_tableAlias}`.`showInMenu` = " . $this->db->quote($value)); break; default: break; } } return $select; } protected function _where(Zend_Db_Select $select = null) { if (null === $select) { $select = $this->select; } $select->where("`{$this->_tableAlias}`.`alias` IS NOT NULL"); if ($this->hasFilter()) { $this->_filterWhere($select); } return $select; } public function draftExists() { $rows = call_user_func_array(array($this->tableDraftPage, 'find'), $this->getPrimaryKey()); if (count($rows)) { return true; } return false; } public function createDraft() { if (false === ($data = $this->_getDataEx())) { return false; } $this->deleteDraftItems($data['id']); $this->_saveDraftDataEx($data); return $this; } public function draftPageOptionExists() { if ($this->isCustomOptions(true)) { $options = $this->getMetaOptions($this->getPrimaryKey(), true, true); return !empty($options); } return true; } public function createPageOptionDraft() { $this->_deleteDraftMetaOptions($this->getPrimaryKey()); $select = $this->db->select(); $select->from( array('po' => $this->_getTableName('PageOption', true)), array('idPage', 'name', 'show', 'value') ); $select->where('`idPage`=' . $this->db->quote($this->getPrimaryKey(), Zend_Db::INT_TYPE)); $data = $this->db->fetchAll($select); if (false === $data) { return false; } $table = $this->_getTable('DraftPageOption', true); foreach ($data as $option) { $table->insert($option); } return $this; } public function getDraftMeta($idPage) { return $this->getMeta($idPage, true); } protected function _getMetaRow($idPage, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $rowset = $this->{"table{$draftPrefix}Page"}->find($idPage); if (!count($rowset)) { return false; } return $rowset->current(); } public function getMeta($idPage, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; if (!($row = $this->_getMetaRow($idPage, $draft))) { return false; } $data = $row->toArray(); $this->_arrayParseTag2Url($data, $this->_urlParseFields['meta']); $content = $this->{"table{$draftPrefix}PageContent"}->select() ->where('idPage = ? ', $idPage) ->where('language = ?', $this->language) ->query() ->fetch(); if (is_array($content) && !empty($content)) { $data = array_merge($data, $content); } return $data; } public function getPages4Select($level = 1, $where = '') { $select = $this->getSelect4SiteMap(); if (is_string($where) && !empty($where)) { $select->where($where); } $select->where("`{$this->_tableAlias}`.`system` <> 'y'"); $siteMap = $this->getSiteMap(array('select' => $select)); $options = $this->_prepareParentOptions($siteMap, $level); return $options; } public function getParent4Select($level = 1, $currPageId = null) { $currPageId = (null === $currPageId) ? $this->getPrimaryKey() : $currPageId; $select = $this->getSelect4SiteMap(); $select->where("`{$this->_tableAlias}`.`id` <> " . (int) $currPageId); $select->where("`{$this->_tableAlias}`.`final` <> 'y'"); $siteMap = $this->getSiteMap(array('select' => $select)); $options = $this->_prepareParentOptions($siteMap, $level); return $options; } protected function _prepareParentOptions($siteMap, $level = 0) { $options = array(); foreach ($siteMap as $page) { $options[$page['id']] = str_repeat(' ', $level * 4) . $page['menuTitle']; if (isset($page['sub'])) { $subOptions = $this->_prepareParentOptions($page['sub'], $level + 1); $options = Qs_Array::mergeAssoc($options, $subOptions); } } return $options; } public function getSelect4SiteMap($options = array()) { if (isset($options['filter'])) { $_filter = $this->_filter; $this->setFilter($options['filter']); } $select = $this->select->reset(); foreach (array('from', 'join', 'where', 'group', 'having') as $name) { $method = '_' . ucfirst($name); $this->$method($select); } $select->order(array($this->_tableAlias . '.idParent', $this->_tableAlias . '.sorter')); if (isset($options['filter'])) { $this->_filter = $_filter; } return $select; } public function getAdditionalSelect4SiteMap($options = array()) { $select = $this->getSelect4SiteMap($options); if (!$this->isCustomOptions()) { return $select; } $select->reset('order'); $select->joinLeft( array('po' => $this->_getTableName('PageOption')), "(`po`.`idPage` = `" . $this->tableAlias . "`.`id`) AND (`po`.`name` = 'isAdditional')", array('isAdditional' => new Zend_Db_Expr('IFNULL(po.value, dpo.value)')) ); $select->joinLeft( array('dpo' => $this->_getTableName('DPageOption')), "`dpo`.`name` = 'isAdditional'", null ); $select->group($this->_tableAlias . '.id'); $select->order(array('isAdditional', $this->_tableAlias . '.idParent', $this->_tableAlias . '.sorter')); return $select; } public function getAllItems() { $select = $this->db->select(); $select->from($this->pairPageItem); $select->order(array('PageItem.idPage', 'PageItem.sorter')); return $this->db->fetchAll($select); } public function getAllItemConfigs() { $select = $this->db->select(); $select->from($this->pairPageItemConfig); return $this->db->fetchAll($select); } public function getAllMetaOptions() { static $data = null; if (null === $data) { $data = array(); $data['defaults'] = $this->getDefaultMetaPairs(); $select = $this->_db->select(); $select->from($this->_getTableName('PageOption', true)); $data['options'] = $this->_db->fetchAll($select); } return $data; } public function getSiteMap($options = array()) { if (empty($options) && empty($this->_filter) && null !== $this->_siteMap) { return $this->_siteMap; } $idParent = 0; if (!isset($options['select'])) { $select = $this->getSelect4SiteMap($options); } extract($options); $_list = $this->_db->fetchAssoc($select); if ($this->isCustomOptions()) { $metaOptions = $this->getAllMetaOptions(); foreach(array_keys($_list) as $k) { $_list[$k] = array_merge($metaOptions['defaults'], $_list[$k]); $this->_arrayParseTag2Url($_list[$k], $this->_urlParseFields['meta']); } foreach ($metaOptions['options'] as $option) { if (array_key_exists($option['idPage'], $_list)) { $_list[$option['idPage']][$option['name']] = $option['value']; } } } if (isset($full)) { // Item Options $itemConfigs = array(); $_itemConfigs = $this->getAllItemConfigs(); foreach ($_itemConfigs as $itemConfig) { if (!array_key_exists($itemConfig['idItem'], $itemConfigs)) { $itemConfigs[$itemConfig['idItem']] = array(); } Qs_Array::set($itemConfigs[$itemConfig['idItem']], $itemConfig['name'], $itemConfig['value']); } // Page Items $items = array(); $_items = $this->getAllItems(); foreach ($_items as $item) { if (array_key_exists($item['id'], $itemConfigs)) { $item['config'] = $itemConfigs[$item['id']]; } $items[$item['idPage']][] = $item; } foreach ($_list as &$page) { if (array_key_exists($page['id'], $items)) { $page['items'] = $items[$page['id']]; } } } $list = array(); foreach($_list as $v) { $list[$v['idParent']][$v['alias']] = $v; } $siteMap = (isset($list[$idParent])) ? $list[$idParent] : array(); unset($list[$idParent]); $parentAlias = ''; if (is_array($siteMap) && !empty($siteMap)) { $this->_prepareSiteMap($siteMap, $list, $parentAlias); } if (empty($options) && empty($this->_filter)) { $this->_siteMap = $siteMap; } return $siteMap; } protected function _prepareSiteMap(&$siteMap, &$list, $parentAlias = '') { foreach ($siteMap as $alias => &$page) { $this->_id2Page[$page['id']] = &$page; $page['fullAlias'] = rtrim($parentAlias, '/') . (($parentAlias) ? '/' : '') . $page['alias']; if (Qs_SiteMap::isSecurePage($page)) { $page['url'] = BASE_URL_LANGUAGE_HTTPS; } else { $page['url'] = BASE_URL_LANGUAGE_HTTP; } if ('y' != $page['isRoot']) { $page['url'] .= ((empty($page['fullAlias'])) ? '' : '/') . $page['fullAlias']; } if (empty($page['header'])) { $page['header'] = $page['title']; } if (empty($page['menuTitle'])) { $page['menuTitle'] = $page['header']; } if (isset($list[$page['id']])) { $page['sub'] = $list[$page['id']]; unset($list[$page['id']]); $this->_prepareSiteMap($page['sub'], $list, $page['fullAlias']); } } } public function getSiteMapPageCount($siteMap) { $count = count($siteMap); foreach ($siteMap as $page) { if (isset($page['sub'])) { $count += $this->getSiteMapPageCount($page['sub']); } } return $count; } public function getDItemType4Select() { if (null === $this->_itemTypes) { $select = $this->_db->select(); $select->from($this->_getTableName('DPageItemType'), array('type', 'title')); $select->order('sorter'); $this->_itemTypes = $this->_db->fetchPairs($select); foreach ($this->_itemTypes as $type => $title) { if (!$this->_itemTypeFileExists($type)) { Qs_Debug::log('Cms item "' . $type . '" not found'); unset($this->_itemTypes[$type]); } } } return $this->_itemTypes; } protected function _itemTypeFileExists($type) { $class = 'App_' . $type . 'View'; $file = BASE_PATH . '/' . str_replace('_', '/', $class) . '.php'; return file_exists($file); } public function getDraftItems($idPage) { return $this->getItems($idPage, true); } public function getItemsList($idPage, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $select = $this->db->select() ->from(array('i' => $this->_getTableName($draftPrefix . 'PageItem'))) ->join(array('g' => $this->_getTableName('DPageItemGroup')), 'g.id = i.idGroup', array('groupTitle' => 'g.title', 'groupName' => 'g.name')) ->where('`i`.idPage = ?', $idPage, Zend_Db::INT_TYPE) ->order(array('g.sorter', 'i.sorter')); $stmt = $select->query(); $items = $stmt->fetchAll(); $sorter = 0; foreach ($items as &$item) { $item['sorter'] = $sorter++; $item['config'] = $this->_getItemConfig($item['id'], $draft); } return $items; } public function getItems($idPage, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $_items = $this->getItemsList($idPage, $draft); $items = array(); foreach ($_items as $item) { if ($itemObject = $this->getItemObject($item['type'])){ $itemObject->setLanguage($this->language); $itemObject->setDraftPrefix($draftPrefix); $itemObject->setPrimaryKey($item['number']); $item['data'] = $itemObject->getData(); } $item['config'] = $this->_getItemConfig($item['id'], $draft); if (!isset($items[$item['groupName']])) { $items[$item['groupName']] = array(); } $items[$item['groupName']]['i'.$item['id']] = $item; } return $items; } public function getDraftItem($id) { return $this->getItem($id, true); } public function getDraftItemRow($id) { return $this->getItemRow($id, true); } public function getItemRow($id, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $rowset = $this->{"table{$draftPrefix}PageItem"}->find($id); if (!count($rowset)) { return false; } return $rowset->current(); } public function getItem($id, $draft = false) { if (! ($row = $this->getItemRow($id, $draft))) { return false; } $item = $row->toArray(); if ($itemObject = $this->getItemObject($item['type'])) { $draftPrefix = ($draft) ? 'Draft' : ''; $itemObject->setLanguage($this->language); $itemObject->setDraftPrefix($draftPrefix); $itemObject->setPrimaryKey($item['number']); $item['data'] = $itemObject->getData(); } $groupData = $this->getItemGroupById($item['idGroup']); if (!empty($groupData)) { $item['groupTitle'] = $groupData['title']; $item['groupName'] = $groupData['name']; } $item['config'] = $this->_getItemConfig($item['id'], $draft); return $item; } public function getItemGroupById($idGroup, $field = null) { $select = $this->db->select(); $select->from($this->pairDPageItemGroup, array('name', 'title')) ->where("`DPageItemGroup`.`id` = " . (int) $idGroup); $data = $this->db->fetchRow($select); if (null !== $field && !empty($data) && array_key_exists($field, $data)) { return $data[$field]; } return $data; } public function getItemObject($type) { $class = 'App_Cms_Item_' . rtrim($type, '_') . '_Obj'; $file = BASE_PATH . '/' . str_replace('_', '/', $class) . '.php'; if (!array_key_exists($class, $this->_itemObjects)) { if (!file_exists($file)) { $this->_itemObjects[$class] = null; } else { $this->_itemObjects[$class] = new $class(); } } if ($this->_itemObjects[$class]) { $this->_itemObjects[$class]->clearData(); } return $this->_itemObjects[$class]; } public function getDraftData($field = false) { return $this->getData($field, true); } public function getData($field = false, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; return Qs_Array::get($this->{'_data' . $draftPrefix}, $field); } public function initDraftData() { $this->_data = $this->getDraftFromDb($this->getPrimaryKey()); } public function getDraftFromDb($idPage, $field = false) { return $this->getFromDb($idPage, $field, true); } public function getFromDb($idPage, $field = false, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; if (null === $this->{'_data' . $draftPrefix}) { $this->{'_data' . $draftPrefix} = array(); if (false !== ($meta = $this->{"get{$draftPrefix}Meta"}($idPage))) { $options = $this->_getPageOptions($idPage, $meta, $draft); foreach ($options as $name => $option) { $meta[$name] = $option['value']; } $this->{'_data' . $draftPrefix}['meta'] = $meta; $items = $this->{"get{$draftPrefix}Items"}($idPage); $this->{'_data' . $draftPrefix} = array_merge($this->{'_data' . $draftPrefix}, $items); } } return Qs_Array::get($this->{'_data' . $draftPrefix}, $field); } public function draftHtmlBlock($idBlock) { $rowset = $this->tableHtmlBlock->find($idBlock); if (!count($rowset)) { return false; } $htmlBlockData = $rowset->current()->toArray(); unset($htmlBlockData['id']); $id_draft_block = $this->tableDraftHtmlBlock->insert($htmlBlockData); $contentItems = $this->tableHtmlBlockContent->select() ->where('idBlock = ?', $idBlock) ->query() ->fetchAll(); foreach ($contentItems as $data) { $data['idBlock'] = $id_draft_block; $this->tableDraftHtmlBlockContent->insert($data); } return $id_draft_block; } public function insertDefaultPage($defaults) { if (isset($defaults['meta'])) { $metaData = $defaults['meta']; } else { $metaData = array(); } if (!empty($defaults['options'])) { $metaOptions = array( 'methods' => array_fill(0, count($defaults['options']), 'insert'), 'options' => array_values($defaults['options']), ); $metaData = array_merge($metaData, $this->extractMeta($defaults['options'])); } else { $metaOptions = null; } $metaData['sorter'] = $this->_getSorter(); $metaData['language'] = DEFAULT_LANGUAGE; $this->_db->beginTransaction(); try { $id = $this->insertMeta($metaData); $this->_updateMetaOptions($metaOptions, false, $id); $itemData = array('idPage' => $id, 'type' => 'HtmlBlock_'); $this->_db->commit(); } catch (Exception $e) { Qs_Debug::log($e->getMessage(), 3); $this->_db->rollBack(); } if (isset($id)) { $this->insertItem($itemData); return $id; } return false; } public function insertDraftMeta($data = array()) { return $this->insertMeta($data, true); } public function insertMeta($data = array(), $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $data['idPage'] = $id = $this->{"table{$draftPrefix}Page"}->insert($data); $this->{"table{$draftPrefix}PageContent"}->insert($data); return $id; } public function insertDraftItem($data) { return $this->insertItem($data, true); } public function insertItem($data, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; unset($data['id']); $this->_db->beginTransaction(); try { if ($itemObject = $this->getItemObject($data['type'])){ $itemObject->setLanguage($this->language); $itemObject->setDraftPrefix($draftPrefix); $itemData = isset($data['data'])?$data['data']:array(); $data['number'] = $itemObject->insert($itemData); } if (!isset($data['sorter'])) { $idGroup = (isset($data['idGroup'])) ? $data['idGroup'] : 1; $data['sorter'] = $this->{"get{$draftPrefix}ItemSorter"}($data['idPage'], $idGroup); } $id = $this->{"table{$draftPrefix}PageItem"}->insert($data); $this->_db->commit(); $this->touch($draft); return $id; } catch (Exception $e) { vdie($e); Qs_Debug::log($e->getMessage(), 3); $this->_db->rollBack(); } return false; } public function getDraftItemSorter($idPage, $idGroup) { return $this->getItemSorter($idPage, $idGroup, true); } public function getItemSorter($idPage, $idGroup, $draft = true) { $draftPrefix = ($draft) ? 'Draft' : ''; $select = $this->_db->select(); $select->from($this->_getTableName($draftPrefix . 'PageItem'), 'MAX(sorter)'); $select->where('`idPage` = ' . $this->db->quote($idPage, Zend_Db::INT_TYPE)); $select->where('`idGroup` = ' . $this->db->quote($idGroup, Zend_Db::INT_TYPE)); $sorter = (int)$this->_db->fetchOne($select); return $sorter; } public function updateDraftItem($id, $type, $data) { return $this->updateItem($id, $type, $data, true); } public function updateItem($id, $type, $data, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; if (!($row = $this->{"get{$draftPrefix}ItemRow"}($id))) { return false; } $this->setPrimaryKey($row->idPage); $this->_db->beginTransaction(); try { if (isset($data['config']) && !empty($data['config'])) { $this->updateItemConfig($id, $data['config'], $draft); } $data['changed'] = date('Y-m-d H:i:s'); $row->setFromArray($data); $row->save(); if (isset($data['data'])) { if ($itemObject = $this->getItemObject($row->type)) { $itemObject->setLanguage($this->language); $itemObject->setDraftPrefix($draftPrefix); $itemObject->id = $row->number; $itemObject->update($data['data']); } } $this->_db->commit(); $this->touch($draft); return true; } catch (Exception $e) { Qs_Debug::log($e->getMessage(), 3); $this->_db->rollBack(); } return false; } public function updateItemConfig($id, array $data, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $data = Qs_Array::collapse($data); $sql = 'DELETE ' . 'FROM ' . $this->db->quoteIdentifier($this->_getTableName("{$draftPrefix}PageItemConfig", true)) . ' ' . 'WHERE `idItem` = ' . $this->db->quote($id, Qs_Db::INT_TYPE); $this->db->query($sql); foreach ($data as $name => $value) { $updateData = array( 'idItem' => $id, 'name' => $name, 'value' => $value ); $this->{"table{$draftPrefix}PageItemConfig"}->insert($updateData); } } public function updateDraftMeta($data = array()) { return $this->updateMeta($data, true); } protected function _metaOptionsFromForm($data = array(), $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $metaOptions = array(); if (false === ($oldValues = $this->getMetaOptions($this->getPrimaryKey(), $draft, true))) { $oldValues = array(); } $defOptions = $this->_getDefaultMetaOptions(); $avaliableOptions = array_keys($defOptions); $defValues = array_merge($defOptions, $oldValues); foreach ($avaliableOptions as $name) { if (!array_key_exists($name, $data)) { continue; } $allowName = $name . '4Dommy'; $method = array_key_exists($name, $oldValues) ? 'update' : 'insert'; $option = array(); $option['idPage'] = $this->getPrimaryKey(); $option['name'] = $name; $option['show'] = array_key_exists($allowName, $data) ? $data[$allowName] : $defValues[$name]['show']; $option['value'] = array_key_exists($name, $data) ? $data[$name] : $defValues[$name]['value']; $metaOptions['methods'][] = $method; $metaOptions['options'][] = $option; } return $metaOptions; } public function updateMeta($data = array(), $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; if ($this->isCustomOptions($draft)) { $metaOptions = $this->_metaOptionsFromForm($data, $draft); } if (isset($data['redirect']) && isset($data['redirectType'])) { if ($data['redirectType'] == 'page' && isset($data['redirectPageId'])) { $data['redirectAlias'] = BASE_URL_LANGUAGE . '/' . Qs_SiteMap::findFirst(array('id' => $data['redirectPageId']), null, null, 'fullAlias'); } $data['redirectAlias'] = str_replace(BASE_URL_LANGUAGE, '{BASE_URL}', $data['redirectAlias']); } unset($data['id'], $data['idPage']); $this->_db->beginTransaction(); try { $this->{"table{$draftPrefix}Page"}->updateByKey($data, $this->getPrimaryKey()); $where = '`idPage` = ' . $this->db->quote($this->getPrimaryKey(), Zend_Db::INT_TYPE) . ' ' . 'AND `language` = ' . $this->db->quote($this->getLanguage()); if ($row = $this->{"table{$draftPrefix}PageContent"}->fetchRow($where)) { $row->setFromArray($data); $row->save(); } else { $data['idPage'] = $this->getPrimaryKey(); $data['language'] = $this->getLanguage(); $this->{"table{$draftPrefix}PageContent"}->insert($data); } if (isset($metaOptions)) { $this->_updateMetaOptions($metaOptions, $draft); } $this->_db->commit(); $this->touch($draft); return true; } catch (Exception $e) { Qs_Debug::log($e->getMessage(), 3); $this->_db->rollBack(); } return false; } protected function _updateMetaOptions($metaOptions = array(), $draft = false, $idPage = null) { if (!$this->isCustomOptions($draft) || empty($metaOptions) || !isset($metaOptions['methods']) || !isset($metaOptions['options'])) { return false; } $idParent = ($idPage) ? intval($idPage) : $this->getPrimaryKey(); $draftPrefix = ($draft) ? 'Draft' : ''; $optionsTable = $this->_getTable($draftPrefix.'PageOption', true); foreach ($metaOptions['methods'] as $key => $method) { if ($method == 'insert') { if (!isset($metaOptions['options'][$key]['idPage'])) { $metaOptions['options'][$key]['idPage'] = $idParent; } $optionsTable->insert($metaOptions['options'][$key]); } else { $where = $this->db->quoteInto('(`idPage`=?) ', $idParent) . $this->db->quoteInto('AND (`name`=?)', $metaOptions['options'][$key]['name']); $optionsTable->update( $metaOptions['options'][$key], $where ); } } return true; } protected function _where4Sorter(Zend_Db_Select $select = null) { if (null === $select) { $select = $this->select; } $select->where("`{$this->_tableAlias}`.`idParent` = ?", $this->idParent); return $select; } public function deleteDraftItem($id_item) { return $this->deleteItem($id_item, true); } public function deleteItem($id_item, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; if (false === ($itemRow = $this->{"get{$draftPrefix}ItemRow"}($id_item))) { return false; }; if ($itemObject = $this->getItemObject($itemRow->type)){ $itemObject->setPrimaryKey($itemRow->number); $itemObject->setDraftPrefix($draftPrefix); $itemObject->delete(); } $this->{"table{$draftPrefix}PageItem"}->delete('`id` = ' . $this->db->quote($id_item, Zend_Db::INT_TYPE)); $this->{"table{$draftPrefix}PageItemConfig"}->delete('`idItem` = ' . $this->db->quote($id_item, Zend_Db::INT_TYPE)); $this->touch($draft); } public function getItemGroupNames() { if (null === $this->_itemGroupNames) { $frontendOptions = array( 'lifetime' => null, 'automatic_serialization' => true ); $backendOptions = array( 'cache_dir' => BASE_PATH . '/tmp/cache/', 'cache_file_umask' => 0664 ); $cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions); if(!$this->_itemGroupNames = $cache->load('PageItemGroupNames')) { $select = $this->_db->select(); $select->from($this->_getTableName('DPageItemGroup'), array('name', 'title')); $select->order('sorter'); $this->_itemGroupNames = $this->_db->fetchPairs($select); $cache->save($this->_itemGroupNames, 'PageItemGroupNames'); } } return $this->_itemGroupNames; } public function getGroupIdByName($name) { $select = $this->_db->select(); $select->from($this->_getTableName('DPageItemGroup'), array('id')); $select->where('`name` = ?', $name); return $this->_db->fetchOne($select); } public function reorderDraftItemsGroup($order) { if (!is_array($order) || empty($order)) { return false; } foreach ($order as $id => $sorter) { $this->tableDraftPageItem->update(array('sorter' => $sorter), 'id = ' . $this->db->quote($id, Zend_Db::INT_TYPE)); } $this->touchDraft(); } protected function _getDraftDataEx() { return $this->_getDataEx(true); } protected function _getDataEx($draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; if (null === $this->_dataEx) { $id = intval($this->getPrimaryKey()); if (!($rowMeta = $this->_getMetaRow($id, $draft))) { return false; }; $this->_dataEx = Qs_Array::exclude($rowMeta->toArray(), 'added', 'changed'); $this->_dataEx['content'] = array(); $stmt = $this->{"table{$draftPrefix}PageContent"}->select() ->where('idPage = ?', $id) ->query(); while ($row = $stmt->fetch()) { $this->_dataEx['content'][$row['language']] = Qs_Array::exclude($row, 'idPage', 'language', 'added', 'changed'); } $this->_dataEx['items'] = array(); $stmt = $this->{"table{$draftPrefix}PageItem"}->select() ->where('idPage = ?', $id) ->query(); while ($row = $stmt->fetch()) { $item = Qs_Array::exclude($row, 'id', 'idPage', 'number', 'added', 'changed'); if ($itemObject = $this->getItemObject($row['type'])){ $itemObject->setDraftPrefix($draftPrefix); $itemObject->setPrimaryKey($row['number']); if ($data = $itemObject->getDataEx()) { $item['data'] = $data; } } $item['config'] = Qs_Array::expand($this->_getItemConfig($row['id'], $draft)); $this->_dataEx['items'][] = $item; } } return $this->_dataEx; } protected function _getItemConfig($idItem, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $select = $this->db->select(); $select->from($this->{"pair{$draftPrefix}PageItemConfig"}, array('name', 'value')); $select->where("`{$draftPrefix}PageItemConfig`.`idItem` = " . $this->db->quote($idItem, Qs_Db::INT_TYPE)); $select->order($draftPrefix . 'PageItemConfig.id'); $data = $this->db->fetchPairs($select); $data = Qs_Array::expand($data); return $data; } protected function _isValidDataEx($data) { if (!is_array($data) || empty($data)) { return false; } $requiredFields = array('id', 'alias', 'content'); foreach ($requiredFields as $name) { if (!array_key_exists($name, $data)) { return false; } } if (!is_array($data['content']) || empty($data['content'])) { return false; } if (isset($data['items'])) { if (!is_array($data['items'])) { return false; } } return true; } protected function _saveDraftDataEx($data) { return $this->_saveDataEx($data, true); } protected function _saveDataEx($data, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; if (!$this->_isValidDataEx($data)) { throw new App_Cms_Exception('Invalid data array'); } $idPage = intval($data['id']); if (!$idPage) { unset($data['id']); } $this->_db->beginTransaction(); try { $idPage = $this->{"table{$draftPrefix}Page"}->save($data, $idPage); foreach ($data['content'] as $language => $content) { $content['idPage'] = $idPage; $content['language'] = $language; $this->{"table{$draftPrefix}PageContent"}->save($content, array($idPage, $language)); } if (!isset($data['items'])) { return $idPage; } foreach ($data['items'] as $item) { if ($itemObject = $this->getItemObject($item['type'])){ $itemObject->setDraftPrefix($draftPrefix); $item['number'] = $itemObject->insertDataEx($item['data']); } $item['idPage'] = $idPage; $idItem = $this->{"table{$draftPrefix}PageItem"}->insert($item); if (isset($item['config']) && !empty($item['config'])) { $this->updateItemConfig($idItem, $item['config'], $draft); } } $this->_db->commit(); return true; } catch (Exception $e) { Qs_Debug::log($e->getMessage(), 3); $this->_db->rollBack(); } return false; } public function publish() { if (false === ($data = $this->_getDataEx(true))) { return false; } if ($this->isCustomOptions(true)) { if (false === ($metaOptions = $this->_getMetaOptions4Publish())) { return false; } $this->_updateMetaOptions($metaOptions, false); } $this->deleteItems($data['id']); $this->_saveDataEx($data, false); $this->clearCache(); $this->_updateRoot(); $this->_updateHasBlocks(); return true; } protected function _getMetaOptions4Publish() { $idPage = intval($this->getPrimaryKey()); $options = $this->getDraftMetaOptions($idPage, true); $oldOptions = $this->getMetaOptions($idPage, false, true); $metaOptions = array(); foreach ($options as $name => $option) { $method = array_key_exists($name, (array)$oldOptions) ? 'update' : 'insert'; unset($option['title']); $option['idPage'] = $idPage; $option['name'] = $name; $metaOptions['methods'][] = $method; $metaOptions['options'][] = $option; } return $metaOptions; } public function updateOrder(array $order) { parent::updateOrder($order); $this->_updateRoot(); } protected function deleteDraftItems($idPage) { return $this->deleteItems($idPage, true); } protected function deleteItems($idPage, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $list = $this->getItemsId($idPage, $draft); foreach ($list as $id_item) { $this->deleteItem($id_item, $draft); } } public function getItemsId($idPage, $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $select = $this->db->select(); $select->from($this->{"pair{$draftPrefix}PageItem"}, 'id'); $select->where("`idPage`=?", $idPage, Zend_Db::INT_TYPE); $list = $this->db->fetchCol($select); return $list; } public function deleteDraft() { return $this->delete(true); } public function delete($draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $idPage = intval($this->getPrimaryKey()); $this->deleteItems($idPage, $draft); $this->{"table{$draftPrefix}Page"}->delete('`id` = ' . $idPage); $this->{"table{$draftPrefix}PageContent"}->delete('`idPage` = ' . $idPage); $this->_deleteMetaOptions($idPage, $draft); $this->clearCache(); } protected function _deleteDraftMetaOptions($idPage = false) { return $this->_deleteMetaOptions($idPage, true); } protected function _deleteMetaOptions($idPage = false, $draft = false) { if (!$this->isCustomOptions($draft)) { return true; } $idPage = ($idPage) ? $idPage : intval($this->getPrimaryKey()); $draftPrefix = ($draft) ? 'Draft' : ''; return $this->_getTable($draftPrefix.'PageOption', true)->delete('`idPage`='.$idPage); } public function getItemTypeTitle($name) { $types = $this->getDItemType4Select(); if (isset($types[$name])) { return $types[$name]; } return null; } public function getLanguageNames() { return array_keys(Qs_Db_Language::getList()); } public function getLanguages() { if (null === $this->_languages) { $this->_languages = Qs_Db_Language::getList(); } return $this->_languages; } protected function _getFullAliasById($id) { if (empty($this->_id2Page)) { $this->getSiteMap(); } if (isset($this->_id2Page[$id])) { return $this->_id2Page[$id]['fullAlias']; } return false; } public function getPageById($id) { return $this->_getPageById($id); } protected function _getPageById($id) { if (empty($this->_id2Page)) { $this->getSiteMap(); } if (isset($this->_id2Page[$id])) { return $this->_id2Page[$id]; } return false; } public function getNotTranslatedPages() { $select = $this->select->reset(); foreach (array('from', 'where', 'group', 'having') as $name) { $method = '_' . ucfirst($name); $this->$method($select); } $select->order(array($this->_tableAlias . '.idParent', $this->_tableAlias . '.sorter')); $select->join(array('cDef' => $this->_getTableName('PageContent')), "`cDef`.`idPage` = `{$this->_tableAlias}`.`id` " . "AND `cDef`.`language` = " . $this->db->quote(Qs_Db_Language::getDefault()), array('cDef.title')); $languages = Qs_Db_Language::getList(); unset($languages[Qs_Db_Language::getDefault()]); $languages = array_keys($languages); foreach ($languages as $language) { $select->joinLeft( array('c' . $language => $this->_getTableName('PageContent')), "`c{$language}`.`idPage` = `{$this->_tableAlias}`.`id` " . "AND `c{$language}`.`language` = " . $this->db->quote($language), array("IF (`c{$language}`.`idPage` IS NULL, 'n', 'y') as isContent" . ucfirst($language))); } $where = array(); foreach ($languages as $language) { $where [] = "(c{$language}.idPage IS NULL)"; } $select->where(implode(' OR ', $where)); $select->order(array($this->_tableAlias . '.idParent', $this->_tableAlias . '.sorter')); $_pages = $this->db->fetchAll($select); $siteMap = $this->getSiteMap(); foreach ($_pages as $page) { $this->_id2Page[$page['id']] = array_merge($this->_id2Page[$page['id']], $page, array('notTranslated' => 'y')); } $this->_prepareSiteMap4NotTranslatedPages($siteMap); return $siteMap; } protected function _prepareSiteMap4NotTranslatedPages(&$siteMap) { foreach ($siteMap as $alias => &$page) { if (isset($page['sub'])) { $this->_prepareSiteMap4NotTranslatedPages($page['sub']); } else { if (!(isset($page['notTranslated']) && 'y' == $page['notTranslated'])) { unset($siteMap[$alias]); } } } } public function clearCache() { $frontendOptions = array( 'lifetime' => null, 'automatic_serialization' => true ); $backendOptions = array( 'cache_dir' => BASE_PATH . '/tmp/cache/', 'cache_file_umask' => 0664 ); $cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions); foreach($this->_cacheId as $id) { $cache->remove($id); } } public function updateIndex($data) { $this->_db->beginTransaction(); try { $table = $this->_getTable("{$this->_tableAlias}Index"); $select = $this->_db->select(); $select->from($this->_getTableName("{$this->_tableAlias}Index"), array('id')); $select->where('`url` = ?', $data['url']); if (!($id = $this->db->fetchOne($select))) { $result = $table->insert($data); } else { $result = $table->updateByKey($data, $id); } $this->_db->commit(); } catch (Exception $e) { Qs_Debug::log($e->getMessage(), 3); $this->_db->rollBack(); return $e; } return $result; } protected function _updateRoot() { $sql = 'UPDATE ' . $this->_db->quoteIdentifier($this->_tableName) . ' SET `isRoot` = \'n\''; $this->db->query($sql); $select = $this->db->select(); $select->from($this->pair, 'id'); $select->where('`Page`.`idParent` = 0'); if ($this->isCustomOptions()) { $select->join($this->pairDPageOption, '`DPageOption`.`name` = "isAdditional"', array()) ->joinLeft($this->pairPageOption, '`Page`.`id` = `PageOption`.`idPage` AND `PageOption`.`name` = `DPageOption`.`name`', array()) ->where('IFNULL(`PageOption`.`value`, `DPageOption`.`value`) = "n"'); } $select->order('Page.sorter'); $select->limit(1); $rootId = $this->db->fetchOne($select); $sql = 'UPDATE ' . $this->_db->quoteIdentifier($this->_tableName) . ' ' . 'SET `isRoot` = \'y\' ' . 'WHERE id = ' . $this->db->quote($rootId, Qs_Db::INT_TYPE); $this->db->query($sql); } protected function _updateHasBlocks() { $select = $this->db->select(); $select->from($this->_tableName . 'Item', new Zend_Db_Expr('1')) ->where('`idPage` = ' . (int) $this->getPrimaryKey()); $hasBlocks = (bool) $this->db->fetchOne($select); $sql = 'UPDATE ' . $this->_db->quoteIdentifier($this->_tableName) . "SET `hasBlocks` = '" . (($hasBlocks) ? 'y' : 'n') . "' " . "WHERE id = " . (int) $this->getPrimaryKey(); $this->db->query($sql); } public function deleteIndex($idPage) { vdie('deleteIndex', $idPage); } public function reindexPage($idPage) { vdie('reindexPage', $idPage); } public function touchDraft() { return $this->touch(true); } public function touch($draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $this->{"table{$draftPrefix}Page"}->updateByKey(array('changed' => date('Y-m-d H:i:s')), $this->_primaryKey); return $this; } public function isCustomOptions($draft = false) { static $result = array(); $_isDraft = (int) $draft; if (empty($result[$_isDraft])) { $draftPrefix = ($draft) ? 'Draft' : ''; $tableName = $this->_getTableName($draftPrefix . 'PageOption', true); $tables = $this->_db->listTables(); $result[$_isDraft] = in_array($tableName, $tables); } return (bool) $result[$_isDraft]; } public function getDraftMetaOptions($idPage, $ignoreDefault = false) { return $this->getMetaOptions($idPage, true, $ignoreDefault); } public function getMetaOptions($idPage, $draft = false, $ignoreDefault = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $ignorePrefix = ($ignoreDefault) ? 'Clean' : ''; if (!isset($this->{"_data{$draftPrefix}{$ignorePrefix}MetaOptions"}[$idPage])) { $options = $this->_getPageOptions($idPage, null, $draft, $ignoreDefault); $this->{"_data{$draftPrefix}{$ignorePrefix}MetaOptions"}[$idPage] = $options; return $options; } else { return $this->{"_data{$draftPrefix}{$ignorePrefix}MetaOptions"}[$idPage]; } } protected function _getPageOptions($idPage, $meta = null, $draft = false, $ignoreDefault = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $pageOptions = ($ignoreDefault) ? array() : $this->_getDefaultMetaOptions(); if (!$ignoreDefault) { if (null === $meta) { $meta = $this->_getMetaRow($idPage, $draft); $meta = ($meta) ? $meta->toArray() : array(); } foreach ($meta as $name => $value) { if (array_key_exists($name, $pageOptions)) { $pageOptions[$name]['value'] = $value; } } } if ($this->isCustomOptions($draft)) { $select = $this->db->select(); $select->from(array('po' => $this->_getTableName($draftPrefix.'PageOption', true))); $select->joinLeft( array('do' => $this->_getTableName('DPageOption'), true), "`do`.`name` = `po`.`name`", array('title') ); $select->where("`po`.`idPage`=?", intval($idPage)); $select->order('sorter'); $data = $this->db->fetchAll($select); foreach ($data as $option) { $pageOptions[$option['name']] = array( 'name' => $option['name'], 'show' => $option['show'], 'value' => $option['value'], 'title' => $option['title'], ); } } return ($ignoreDefault && empty($pageOptions)) ? false : $pageOptions; } protected function _getDefaultMetaOptions() { static $pageOptions = null; if (null === $pageOptions) { $pageOptions = array( 'showInSiteMap' => array('show' => 'y', 'value' => 'n', 'title' => 'Show in Sitemap'), 'showInMenu' => array('show' => 'y', 'value' => 'n', 'title' => 'Show in Menu'), 'allowDelete' => array('show' => 'n', 'value' => 'n', 'title' => 'Allow delete'), 'isSecure' => array('show' => 'n', 'value' => 'y', 'title' => 'Secure page'), 'isIndexing' => array('show' => 'n', 'value' => 'n', 'title' => 'Include this page in search results'), 'final' => array('show' => 'n', 'value' => 'n', 'title' => 'Final page'), 'system' => array('show' => 'n', 'value' => 'n', 'title' => 'System (hidden in admin end)'), ); if ($this->isCustomOptions()) { $availableOptions = $this->_get4Select( 'DPageOption', array('name','title','show','value'), true ); $pageOptions = array_merge($pageOptions, $availableOptions); } } return $pageOptions; } public function getDefaultMetaPairs() { static $result = null; if (null === $result) { if ($this->isCustomOptions()) { $result = $this->_get4Select('DPageOption', array('name', 'value'), true, null, 'sorter'); } else { $result = array(); } } return (array) $result; } protected function extractMeta($options) { if (!is_array($options)) { return false; } $meta = array(); foreach ($options as $name => $option) { $meta[$name] = (is_array($option)) ? $option['value'] : $option; } return $meta; } public function isRedirectFields() { $redirectFields = array('redirect', 'redirectType', 'redirectPageId', 'redirectStatus', 'redirectAlias'); $metaData = $this->_getTable($this->_tableAlias)->getMetaData(); $diff = array_diff($redirectFields, array_keys($metaData)); if (empty($diff)) { return true; } return false; } public function getReorderOptions($keyColumn, $titleColumn, $isAdditional = null) { $select = $this->getListSelect(); if (0 === $this->idParent && null !== $isAdditional) { $select->joinLeft( array('po' => $this->_getTableName('PageOption')), "(`po`.`idPage` = `" . $this->tableAlias . "`.`id`) AND (`po`.`name` = 'isAdditional')", array('po.value') ); $select->group($this->_tableAlias . '.id'); if (true === $isAdditional) { $select->where("po.value = 'y'"); } else { $select->where("po.value IS NULL OR po.value = 'n'"); } } $select = $this->_where4Sorter($select); $select->order($this->_tableAlias . '.sorter'); $list = $this->_db->fetchAll($select); $options = array(); foreach ($list as $row) { $options[$row[$keyColumn]] = $row[$titleColumn]; } return $options; } public function updateDraftMetaRow($data = array()) { return $this->updateMetaRow($data, true); } public function updateMetaRow($data = array(), $draft = false) { $draftPrefix = ($draft) ? 'Draft' : ''; $this->{"table{$draftPrefix}Page"}->updateByKey($data, $this->getPrimaryKey()); } }