Как истинный консерватор, я долгое время использовал исключительно MODx Evolution. Меня устраивало прежде всего наличие исчерпывающей документации, кучи статей и предельно понятной архитектуры данной версии MODx CMF. О версии Revolution я периодически читал разные статьи, но мне не хотелось менять привычную для меня систему на что-либо другое. Однако, в один прекрасный момент количество таблиц в базе данных моего мультидоменного «хомячка» на
Первое, что приходит в голову — это использовать уже проверенный популярный код:
switch($_SERVER['SERVER_NAME']) {
case 'sub1.domain.tld': $modx->initialize('sub1'); break;
case 'sub2.domain.tld': $modx->initialize('sub2'); break;
case 'sub3.domain.tld': $modx->initialize('sub3'); break;
default: $modx->initialize('web');
}
Если, скажем, у Вас на системе контекстов зиждется многоязычность, тогда можно сделать даже так:
switch($_SERVER['SERVER_NAME']) {
case 'domain.ru': case 'www.domain.ru': $modx->initialize('ru'); break; // Переключаем на русский
case 'domain.fr': case 'www.domain.fr': $modx->initialize('fr'); break; // Переключаем на французский (для примера)
default: $modx->initialize('web');
}
И для не сильно больших порталов, где число поддоменов контролируется администратором хостинга/домена и редко меняется, такого решения хватит за глаза. Однако, давайте с Вами пофантазируем. Есть у Вас свой сервер. Это может быть Ваш личный сервер или VDS-ка на любимом
Создать контекст при помощи API не сильно сложно. Вдаваться в подробности я не стану, не слишком сильно пока что изучил API MODx Revolution. Тем не менее создать контекст и поддомен — это одно, а вот связать это воедино — другое. Здесь вышеуказанные решения не подойдут, ибо заранее неизвестно сколько будет поддоменов и как будут называться контексты для них. По идее, если алиасы контекстов совпадают с именами поддоменов, тогда вполне подойдёт решение:
define("myRootDomain","domain.tld");
$ctxKey = 'web';
if (preg_match('#(w+).'.myRootDomain.'#si',$_SERVER['SERVER_NAME']) > 0) {
$ctxKey = preg_replace('#(w+).'.myRootDomain.'#si','1',$_SERVER['SERVER_NAME']);
if ($ctxKey == 'www') $ctxKey = 'web';
}
Основная информация о контекстах в MODx хранится в БД в таблицах context, context_setting. В первой таблице находятся описания контекстов (ключ, описание, порядок отображения). Во второй — настройки контекста. Помните, в распространённых решениях нам нужно было прописывать страницы ошибок, хост и тому подобное? Вот это-то всё там и хранится. И первое, что приходит в голову — это SQL-запрос к этой таблице:
$SQL = "SELECT * FROM ".$table_prefix." WHERE `key`='http_host' AND `value`='".$_SERVER['SERVER_NAME']."'";
Если бы система контекстов была предусмотрена в старушке Evolution, тогда с алгоритмом всё было бы просто:
$ctxKey = 'web';
if ($result = $modx->db->query($SQL)) if ($row = mysql_fetch_assoc($result)) $ctxKey = $row['context_key'];
Однако, в этом отношении разработчики MODx подложили разработчикам, использующим MODx, небольшую хрюшку, ибо архитектура MODx Revolution зиждется на xPDO. А это уже не привычное нам API, а совсем другой разговор.
Изучив кучу результатов гугло-поиска, в том числе и официальную документацию на MODx Revolution API, я так и не смог понять, как проще сделать запрос к БД в MODx Revolution. Зато, копнув файл core/model/modx/modx.php, я обнаружил нечто следующее:
$pluginEventTbl= $this->getTableName('modPluginEvent');
$eventTbl= $this->getTableName('modEvent');
$pluginTbl= $this->getTableName('modPlugin');
$propsetTbl= $this->getTableName('modPropertySet');
$sql= "
SELECT
Event.name AS event,
PluginEvent.pluginid,
PropertySet.name AS propertyset
FROM {$pluginEventTbl} PluginEvent
INNER JOIN {$pluginTbl} Plugin ON Plugin.id = PluginEvent.pluginid AND Plugin.disabled = 0
INNER JOIN {$eventTbl} Event ON {$service} Event.name = PluginEvent.event
LEFT JOIN {$propsetTbl} PropertySet ON PluginEvent.propertyset = PropertySet.id
ORDER BY Event.name, PluginEvent.priority ASC
";
$stmt= $this->prepare($sql);
if ($stmt && $stmt->execute()) {
while ($ee = $stmt->fetch(PDO::FETCH_ASSOC)) {
$eventElementMap[$ee['event']][(string) $ee['pluginid']]= $ee['pluginid'] . (!empty($ee['propertyset']) ? ':' . $ee['propertyset'] : '');
}
}
Это фрагмент метода getEventMap класса modX. Логично предположить, что вместо длиннющего запроса мы можем вставить свой запрос и он по идее должен отработать, как нужно. В результате рождается решение:
$ctxCur = 'web';
$ctxQur = "SELECT * FROM `".$table_prefix."context_setting` WHERE `key`='http_host' AND `value`='".$_SERVER['SERVER_NAME']."'";
$ctxSQL = $modx->prepare($ctxQur);
if ($ctxSQL && $ctxSQL->execute()) if ($ctxRes = $ctxSQL->fetch(PDO::FETCH_ASSOC)) $ctxCur = $ctxRes['context_key'];
$modx->initialize($ctxCur);
При использовании данного решения нам нужно заботиться лишь о правильном указании поля http_host в админке. И имя контекста в этом случае не обязательно должно совпадать с поддоменом. На сим всё. Спасибо за внимание к моему очередному велосипеду!
Автор: XanderBass