Как стать автором
Обновить

Страдания по CMF или Zend + Doctrine. Часть 1

Время на прочтение6 мин
Количество просмотров615
Попытки создания собственной системы начались довольно давно (думаю это всем знакомо). За последние пару лет была откатана схема на своей системе, но сама система благополучно почила в бозе. Если там были попытки как-то использовать Zend как компоненты, то в конце концов было принято решение не изобретать велосипед, а просто взять Zend за основу.
Zend — 1.8/Doctrine — 1.1 на момент написания.

Что было решено сохранить в системе из предыдущей версии
1) Мультисайтовость
2) Мультиязычность. Интернационализация производится за счет Zend и Doctrine.
3) Модульность. При этом создать модуль можно в самой системе, задав yaml схему и получив стандартные методы для работы с помощью контроллеров и автогенерированых форм (Zend_Form).
4) В создаваемых модулях по умолчанию присутствует поддержка i18n, versionable, timestampable.
Каждый сайт имеет режимы отображения — backend, frontend,etc. Модель — одна для всех. Основой для моделей выбрана Doctrine. Показалась очень удобной.

Соотвественно схема приложения получилась следующая:
/application
--->/backend
------>/helpers
------>/languages
------>/layouts
------>/modules
--->/frontend
--->/installer
/models
/tests
/library
--->/Xms
--->/Xms/Core
--->/Xms/Backend
--->/Xms/Frontend
--->/Zend
--->/Doctrine

При запуске приложения определяется в каком режиме оно запускается, после чего стартует Boostrap. Можно использовать тот, что по умолчанию находится в /application. Можно (как сделано в случае инсталлера) определить свой.
Запуск приложения
$application = new Xms_Application(<br/>
                            APPLICATION_ENV,<br/>
                            array('config' => XMS_ROOT . '/config/application.ini',<br/>
                            'mode' => 'backend')<br/>
                            );<br/>
$application -> setBootstrap(APPLICATION_PATH . '/Bootstrap.php');<br/>
$application->bootstrap()->run();



Класс Xms_Application производит первичную инициализацию
require_once 'Zend/Loader/Autoloader.php';<br/>
require_once( 'Doctrine.php' );<br/>
Zend_Loader_Autoloader::getInstance()<br/>
                  ->pushAutoloader(array('Doctrine', 'autoload')); <br/>
Zend_Loader_Autoloader::getInstance()->registerNamespace('Xms_');<br/>
Zend_Loader_Autoloader::getInstance()->registerNamespace('Scienta_');



Класс Bootstrap унаследован от Xms_Core_Abstract, который в свою очередь унаследован от Zend_Application_Bootstrap_Bootstrap. Метод run:
     $this -> _readConfig();<br/>
     $this -> _setDb();<br/>
     $this -> _setEnvironment();<br/>
     $this -> _setLayout();<br/>
     $this -> _setSystem();<br/>
     $this -> _setSecurity();<br/>
 <br/>
     Zend_Registry::set( 'Xms_Bo', $this );<br/>
     parent::run();


Немного подробнее о методах _setEnvironment(), _setSystem() и _setSecurity()
_setEnvironment()
protected function _setEnvironment()<br/>
{<br/>
Doctrine::loadModels(array(<br/>
        XMS_ROOT . DIRECTORY_SEPARATOR . <br/>
            Xms_Application::APPLICATION_FOLDER . DIRECTORY_SEPARATOR . <br/>
            Xms_Application::MODELS_FOLDER . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR .<br/>
            Xms_Application::MODELS_FOLDER_GENERATED,<br/>
        XMS_ROOT . DIRECTORY_SEPARATOR . <br/>
            Xms_Application::APPLICATION_FOLDER . DIRECTORY_SEPARATOR . <br/>
            Xms_Application::MODELS_FOLDER . DIRECTORY_SEPARATOR . 'core'<br/>
                                )<br/>
                            );<br/>
    $this->_defineUri();<br/>
    $this->_loadModes();<br/>
    $this->_loadSites();<br/>
    $this->_loadModules();<br/>
    $this->_loadLanguages();<br/>
    $this->_loadRouters();<br/>
}


Тут происходит инициализация приложения — загрузка доступных режимов, сайтов, модулей, локалей и роутеров.

_setSystem()
foreach($this->_moduleMatrix as $key=>$val){<br/>
    $front->addControllerDirectory(XMS_ROOT . DIRECTORY_SEPARATOR .<br/>
        Xms_Application::APPLICATION_FOLDER . DIRECTORY_SEPARATOR .<br/>
        Xms_Application::APPLICATION_EXT . DIRECTORY_SEPARATOR .<br/>
        $this->_mode . DIRECTORY_SEPARATOR . Xms_Application::MODULES_FOLDER . DIRECTORY_SEPARATOR . $key, $key);<br/>
}


Здесть происходит установка модулей. То есть модуль у которого нет связи с запускаемым сайтом — не будет доступен.

_setSecurity()
$this->_acl = new Xms_Core_Acl($this->_siteId, $this->_modeId);<br/>
$front->registerPlugin(new Xms_Core_Controller_Plugin_auth(Zend_Auth::getInstance(), $this->_acl));



С точки зрения разграничения прав доступа решено было остановиться на том, что конечным ресурсом будет не Zend_Action, а собсно сам контроллер. Ну просто представим ситуацию когда в контроллер добавлено новое действие (что в случае с тем же AJAX более чем вероятно) и процедуру изменения ролей и грантования прав доступа на новое действие:)

Doctrine-зация
Вот за что особая благодарность разработчикам Doctrine — за Doctrine_Template.
Задача: по умолчанию таблицы создаются с поддержкой Doctrine_I18n, Versionable, SoftDelete и Timestampable. Была проблема — trac.doctrine-project.org/ticket/1708. Наследованием и удалением ненужного референса удалось по быстрому от этого уйти. Кроме того, теперь каждая запись характеризуется также принадлежностью пользователю и сайту.

Что имеем на данный момент.
1) Режим инсталлера. Установка системы.
2) Режим backend. Добавление модуля приводит к тому, что создаются таблицы, контроллеры и формы.
3) Режим frontend в зачатчном состоянии. Думается использование Action_Stack для формирования страниц в соотвествии с подключенными к этой странице модулямя.

Системе кроме разграничения прав доступа к действиям необходимо иметь разграничение прав к данным. Роль будет иметь кроме доступа к ресурсам контроллеров также доступ к срезу данных. Срез формируется на основание доступа к каждому полю таблицы.

Хотелось бы использовать Zend_Project для генерации новых режимов — думается о режиме opensocial (социалка с поддержкой code.google.com/intl/ru/apis/opensocial), office (раз схемы можно генерировать из yaml, то почему нельзя дать графический инструмент создания таблиц), jquery-grid и тд.
Учитывая Doctrine_Event сделать систему запуска процесса. То есть созданная кем то установка — при добавлении записи в таблицу А вызвать добавление записи в таблицу Б и отправку емайла должна сработать.

Вот такая попытка описать вкратце то, что получилось. Спасибо хабраюзерам за заметки со своим опытом — значит не только нам интересно изобретать велосипед:)
Код планируется выложить в OpenSource, так что если кому интересно будет посмотреть-пощупать — велкам.
Теги:
Хабы:
+6
Комментарии10

Публикации