Pull to refresh

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

Reading time6 min
Views616
Попытки создания собственной системы начались довольно давно (думаю это всем знакомо). За последние пару лет была откатана схема на своей системе, но сама система благополучно почила в бозе. Если там были попытки как-то использовать 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, так что если кому интересно будет посмотреть-пощупать — велкам.
Tags:
Hubs:
Total votes 8: ↑7 and ↓1+6
Comments10

Articles