Итак, в ходе долгих раздумий, рассмотрении плюсов и минусов реализации региональности, было принято решение разворачивать регионы на поддоменах.
Собственно решение обоснованное, с учетом трудозатрат, понимания, расширяемости и т.п.
Т.к. это решение пришло после реализации региональности в компоненте, то естественно хороший или не очень код отправляется в комментарии.
Приведу сразу же код роутера и модели, м.б. кому-нибудь поможет.
Сначала router.php
<?php
/**
* @package Joomla.Site
* @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
jimport('joomla.application.categories');
/**
* Build the route for the com_content component
*
* @param array An array of URL arguments
* @return array The URL arguments to use to assemble the subsequent URL.
* @since 1.5
*/
function XbanerBuildRoute(&$query)
{
// $query должно иметь вид index.php?option=com_xbaner&view=xbaner&catid=ид_категории, т.е никаких
// няшек и рюшек типа ид_категории:алиас. Алиас получаем в самом роутере.
$app = JFactory::getApplication();
$menu = $app->getMenu();
$segments = array();
$menuItem = $menu->getItems('link','index.php?option=com_xbaner&view=xbaner&catid='.$query['catid'], true); // получаем первый пункт меню по catid
if(!$menuItem){//если пункта с таким catid не существует - будем делать свой.
$menuItem = $menu->getActive();//вот это самая геморная часть. Если не получить активный пункт меню, модуль меню не будет работать.
$categories = JCategories::getInstance('xbaner');
$category = $categories->get($query['catid']);//получаем эту самую категорию по catid
if (!$category) {//если её нету, то извините :)
return $segments;
}
if(isset($query['region'])){
$db =&JFactory::getDBO();
$DBload = 'SELECT alias FROM #__region WHERE id='.(int)$query['region'];
$db->setQuery($DBload);
$alias = $db->loadResult();//этот запрос получает алиас из БД
$query['region'] = $alias;//устанавливаем $query['id'] равным ид_итема:алиас
$segments[] = $query['region'];
unset($query['region']);
}else{
$path = $category->getPath();//получаем путь категории вида Array([0]=>ид_категории:алиас [1]=>ид_категории:алиас и т.д.). Массив, потому что получаем полный путь категории начиная от корневого пункта меню.
$segments = array_merge((array)$segments, (array)$path);//добавляем этот путь в результирующий массив $segments
}
}
$itemid = $menuItem->id; //важный момент! получаем Id пункта меню. В любом случае он будет, либо активного, либо полученного вначале.
if (empty($query['Itemid'])){//устанавливаем Itemid
$query['Itemid']=$itemid;
}
elseif($menuItem->query['catid']==$query['catid']){//без этого условия модуль меню не будет работать
$query['Itemid']=$itemid;//условие проверяет сопоставление catid. В модуле меню они не равны
}
unset($query['catid']);
if(isset($query['id']))//т.к. итемам не присваивают пункты меню, алиас будем для них формировать всегда
{
if (strpos($query['id'], ':') === false) {//эту проверку можно исключить, но на всякий случай :)
$db =&JFactory::getDBO();
$DBload = 'SELECT alias FROM #__xbaner WHERE id='.(int)$query['id'];
$db->setQuery($DBload);
$alias = $db->loadResult();//этот запрос получает алиас из БД
$query['id'] = $query['id'].':'.$alias;//устанавливаем $query['id'] равным ид_итема:алиас
}
$segments[] = $query['id'];
unset($query['id']);
};
unset($query['view']);//мне не нужен в строке вид, если хотите, можете и его передать.
return $segments;
}
/**
* Parse the segments of a URL.
*
* @param array The segments of the URL to parse.
*
* @return array The URL attributes to be used by the application.
* @since 1.5
*/
function XbanerParseRoute($segments)
{
$vars = array();
$count = count($segments);
list($id, $alias) = explode(':', $segments[$count-1], 2);//берем последний элемент массива и разбиваем связку ид:алиас
$category = JCategories::getInstance('xbaner')->get($id);//подгружаем по ID категорию
if((strpos($segments[$count-1], ':') === false) && $count==1){
$vars['view']='xbaner_index';
$vars['region']= $_COOKIE['geobase'];
return $vars;
}elseif ($category && $category->alias==$alias){//если категория существует и алиасы совпадают
$vars['view']='xbaner';//устанавливаем нужный вид
$vars['catid']=$id;//и ид категории
return $vars;//на этом все! больше ничего не требуется
}else{//если категории не существет, то это итем
$db =&JFactory::getDBO();
$DBload = 'SELECT alias FROM #__xbaner WHERE id='.(int)$id;
$db->setQuery($DBload);
$alias_db = $db->loadResult();//этот запрос получает алиас из БД
if ($alias==$alias_db){
$vars['view'] = 'xbaner_one';//ставим вид нужный
$vars['id'] = (int)$id;//и ид_итема
return $vars;//делаем "давай дасвидания!"
}
}
return $vars;
}
Сейчас могут опять же возникнуть некоторые недоразумения, например, зачем проверять алиас? Решение это обосновано тем, что если не сделать проверку, то можно написать любой алиас с нужным id и итем все равно отобразиться верно, что не есть хорошо. Было мнение, что нужно проверять алиас в модели, но я предпочел данный метод, он гораздо проще.
А вот это модель главной страницы.
<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import Joomla modelitem library
jimport('joomla.application.component.modelitem');
/**
* Xbaner_index Model
*/
class XbanerModelXbaner_index extends JModelItem
{
/**
* @var object item
*/
protected $item;
protected $maker;
protected $stage;
/**
* Returns a reference to the a Table object, always creating it.
*
* @param type The table type to instantiate
* @param string A prefix for the table class name. Optional.
* @param array Configuration array for model. Optional.
* @return JTable A database object
* @since 2.5
*/
public function getTable($type = 'Xbaner', $prefix = 'XbanerTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
/**
* Get the message
* @return object The message to be displayed to the user
*/
protected function getListQuery()
{
$region = JRequest::getVar('region');
$url = JURI::current();
$baseurl = JURI::base();
if ((!$region || $url==$baseurl) && isset($_COOKIE['region'])){
JFactory::getApplication()->redirect(JRoute::_('index.php?option=com_xbaner&view=xbaner_index®ion='.$_COOKIE['region']));
}else{
if (!$region){
$plugin = JPluginHelper::getPlugin('system', 'geo');
$pluginParams = new JRegistry();
$pluginParams->loadString($plugin->params);
$param = $pluginParams->get('home_item');
JFactory::getApplication()->redirect(JRoute::_('index.php?option=com_xbaner&view=xbaner_index®ion='.$param));
}
$db = JFactory::getDBO();
$query = $db->getQuery(true);
// Select some fields
$query->select('#__xbaner.*, #__categories.lft');
$query->from('#__xbaner');
$query->where("#__xbaner.published=1 AND #__xbaner.type=1 AND #__xbaner.region LIKE '%$region,%' or region LIKE '$region,%' or region LIKE '%,$region' or region=$region");
$query->join('', '#__categories ON #__xbaner.catid = #__categories.id');
$query->order('#__categories.lft');
$db->setQuery($query);
$array = $db->loadAssocList();
if (empty($array)) {
return JError::raiseError(404, JText::_('ERROR! BANER NOT FOUND!'));
}
return $array;
}
}
protected function getListOld(){
$this->_db->setQuery($this->_db->getQuery(true)
->from('#__maker')
->select('*')
->where('published=1 ORDER BY id'));
$array = $this->_db->loadAssocList('id');
return $array;
}
public function getItem()
{
if (!isset($this->item))
{
$this->item = $this->getListQuery();
}
return $this->item;
}
public function getMaker()
{
if (!isset($this->maker))
{
$this->maker = $this->getListOld();
}
return $this->maker;
}
}
Тут нас интересует getListQuery(), как видите, сделаны всяческие проверки, дабы исключить ошибки.
Думаю некоторые заметят, что подгружается плагин
geo. Это системный плагин, который записывает id региона в кукисы, регион определяется сервисом ipgeobase.ru.
Получается, что для реализации региональности, в купе идут 2 компонента(компонент регионов и компонент каталога) и плагин. Региональность новостей ещё не готова. Только
плагин-кнопка.
Вообще привожу код здесь только для тех, кто когда-нибудь в своем компоненте захочет реализовать нечто подобное.