пятница, 11 декабря 2009 г.

Ядро CMS. Поддержка языков в системе. Часть 2.

Когда мы говорим о ядре CMS то подразумеваем некую часть системы, которая выполняется при любом запросе. Исключение, когда включен полностраничный кеш -- тогда выборка из кеша может происходить на начальных этапах запуска системы и дальше управление просто не передается.

Итак, нам следует определиться с основой системы. Или это некий фреймверк (в моем случае, это CodeIgniter) или же система пишется полностью с нуля, но тогда следует все равно написать некоторый каркас. Я советую использовать любимый фреймверк, иначе придется написать довольно много рутинного кода.

То с чем буду работать я:CodeIgniter 1.7.1 + HMVC с множественными правками и дополнениями (о деталях чуть позже).

Итак. Мы хотим что бы наша система имела поддержку многоязычности на уровне ядра. Как обсуждалось ранее, наиболее удачным сегментом адреса для определения языка является самый первый сегмент.


Здесь, следует оговориться, я предполагаю, что читатель имеет какое-то представление о фреймверках и патерне MVC

В разговоре (если это разговор) прозвучало слово ядро.
В моем понимании

Ядро системы -- это не изменяемая часть системы, дающая возможность функционировать всему приложению в целом.

Проще говоря, ядро -- это основа, набор базовых классов и методов реализующих жизненный цикл приложения. Приложение может расширять свой функционал за счет добавления модулей которые работают/взаимодействуют (обычно) через интерфейсы ядра.

Ядро


Что мы можем назвать ядром системы в контексте приложения MVC?
Этим может стать библиотека (как было описано в истории о первой попытке разработать свою CMS). Она может быть загружена через автозагрузку фреймверка (файл config/autoload.php в случае CodeIgniter) или же быть вызванной еще на начальных этапах загрузки... Но это чревато проблемами, да и в принципе, не логично.

При загрузке операционной системы, после старта загрузчика, загрузчик запускает сразу ядро операционной системы. Вспомнив об этом, я пришел к выводу, что ядром должен являться контроллер.

Можно поспорить, что контроллер это унифицированный элемент приложения решающий конкретные задачи. Правильно -- вот пусть и решает задачу ядра системы. По сути, все что нам от него нужно -- это разобраться что хочет пользователь и запустить соответствующий модуль. А дальше, дальше модуль решает, что будет происходить в системе.


Если кто-то напуган такой простотой описания -- не переживайте. Эти общие слова лишь вступление.

Контроллер, он же ядро должен иметь метод который будет вызываться всегда при запуске системы. Это может быть магический метод класса __call.
Магический метод __call -- начиная с php5 наличие этого метода в классе автоматически переопределяет вызовы всех методов класса на него. При этом, в первом параметре передается имя вызываемого метода, а во втором массив аргументов с которыми вызван метод. Главное достоинство -- возможность перехватить вызов не существующего метода класса. Подробнее
Или же, как в случае с CodeIgniter метод _remap.
Метод _remap -- для CodeIgniter выполняет туже роль, что может играть и __call для php5, но т.к. CodeIgniter нацелен на поддержку php4, то используется собственная реализация.
Что выбирать, решать Вам.
Я выбрал второй вариант по двум причинам:
  1. Я придерживаюсь правила -- Минимум правок самого фреймверка.
  2. Этот механизм ближе идеологии фреймверка

В целом, если Вы для разработки решили использовать другой фреймверк, то Вам не сложно будет адаптировать мои советы для Вашего случая.

Таким образом, у нас есть метод который будет вызываться при любых вызовах нашей системы. То, какие параметры в него будут передаваться -- это уже другая история. Главное -- мы определили точку входа приложения.

URL


Т.к. большинство фреймверков (если не все) разбирают строку адреса следующую за доменным именем как

контроллер/метод/параметры/параметры...

То средствами роутинга Вашего фреймверка следует заставить читать строку адреса иначе. Нужно переопределить все вызовы на один контроллер -- на ядро системы.

Для CodeIgniter это выглядит так:


$route['default_controller'] = "kernel";
$route['(.+)'] = 'kernel/$1';

Для других фреймверков -- обратитесь к их руководствам.

Первой строкой мы указали, что контроллер по умолчанию (когда сайт вызван без параметров) это тоже наше ядро, а второй попросили любые запросы передавать в наш контроллер, который по совместительству является ядром.

Здесь можно оговориться и сказать, что данное переопределение можно реализовать и средствами того же mod_rewrite. Да, возможно. На первый взгляд кажется, что будет даже лучше, но только на первый. Как нибудь потом можно будет остановиться на таких вопросах подробнее.

А как же языки системы? Про них не забыли? Спросите Вы. Нет... вспомним и про них.

Язык


Итак, мы определились с ядром и его методом который будет вызываться для обработки любых запросов к системе.

И как раз здесь и стоит вспомнить о языках.

Единая точка входа (__call, _remap) это то место в системе, где и следует произвести всю работу касательно определения языка.

Все просто. В самом начале работы этого метода мы проверяем конфигурацию системы на предмет Использует ли сайт многоязычность? Если да -- мы загружаем модуль со строго определенным именем Languages и просим его разобраться с первым сегментом строки адреса.

Copy Source | Copy HTML
  1. public function _remap($module)
  2. {
  3.     //запрашиваем массив всех сегментов строки адреса
  4.     $params = $this->uri->rsegment_array();
  5.  
  6.     if($this->config->item('use_multi_language')){
  7.         //загружаем модуль поддержки языков
  8.         $this->module('languages');
  9.  
  10.         if(!$this->languages->isLanguageAlias($params[2])){
  11.             $slng = $this->languages->getDefaultLanguageAlias();
  12.         } else {
  13.             $slng = $params[2];
  14.         }
  15.  
  16.         $this->languages->setSystemLanguage($slng);
  17.  
  18.         $this->cache->initialize(array('sLng' => $slng));
  19.     } else {
  20.  
  21.     }
  22. }
  23.  

4 - фреймверк возвращает нам массив сегментов строки адреса после обработки правилами роутинга. Нумерация элементов в массиве начинается с 1 (особенность CodeIgniter). В первом элементе массива, будет имя нашего контроллера.

10 - Модуль языков проверяет (isLanguageAlias), является ли сегмент алиасом одного из языков системы.

11 - если нет, чтож, забыли указать язык, берем язык по умолчанию (getDefaultLanguageAlias).

16 - устанавливаем найденный язык (или язык по-умолчанию) как системный. Там может происходить много вещей, о которых мы поговорим чуть позже.

18 - забегая вперед, это установка языка для кеша. Думаю, общий смысл понятен, а о деталях я расскажу позже.

Конечно, это далеко не полный код метода ядра и уж тем более всего ядра. Это только часть касательно языка.

Далее происходит очистка параметров от языка. Это делается для универсализации последующего кода, т.к. если модуль работает с языками, то он может обратиться непосредственно к модулю языка и получить от него все что ему нужно для работы.

На этом, пожалуй, стоит остановиться.

P.S. хотелось бы увидеть комментарии читателей о всем написанном.

4 комментария:

MpaK комментирует...

Kernel пишется с одним L :)

Мы так же разрабатываем CMS на базе CI, у нас всё скидывается на один контроллер core, он уже разбирает путь из базы и подключает другие контролеро-модули через HMVC

Языки и в целом интернациализация через gettext

Unknown комментирует...

Спасибо, за комментарий. Очепятку исправил.
Рад, что это еще кому-то интересно.

MpaK комментирует...

да я так, слежу по РСС, но вижу, что ты как-то странно движешься :(

"Нумерация элементов в массиве начинается с 1 (особенность CodeIgniter)"
это чушь, не CI тут он не меняет нумерацию, 0 тоже есть, просто он предлагает возможность удобной нумерации :)

Ну а в целом, я понимаю твоё желание велосипеда и попробую в какой-то момент отрыть исходники нашей системы на CI, чтобы обсудить с человеком которому хочется писать...
зы. попробуем тут http://ufacode.ru

Unknown комментирует...

Вы меня, вероятно, не так поняли. Система уже написана и испытанна в работе. И вполне отлично справляеться работая на нескольких проектах и еще несколько готовяться к запуску. В скором времени система станет доступной для скачивания и свободного использования.

Здесь же я пишу заметки для тех кто только хочет написать свою систему. Т.к. когда писал я свою (уж вторую) CMS -- я не нашел в интернете ни какой адекватной информации. При разработке своего движка возникает множество проблем которые каждый решает по своему. Но вот варианты решения никогда не помешают новичкам.

Я бы мог даже предложить другим разработчикам, имеющим свои разработанные системы предлагать свои варианты решения тех задач которые я буду описывать. Думаю, это пойдет всем только на пользу.

Я очень хорошо знаком с CI. Нумерация действительно начинается с 1. Изучите документацию, нулевой элемент не представляет важности в обсуждаемом контексте.