Документация

Что такое CompleXml Framework
Требования
Установка и настройка CompleXml
Особенности и отличия
Начало работы
Создание проекта
Структура проекта
Настройка проекта
Алгоритм обработки запроса
Работа с View
Конфигурирования CompleXml Framework
Работа с базами данных
Кеширование
Множества данных (Сессии, Куки, Request, POST, GET)
Авторизация и права доступа
Ведение журналов (Logs)
Производительность CompleXml

Что такое CompleXml Framework

CompleXml Framework - быстрый, расширяемые, производительный, открытый php framework. Предназначен для быстрой разработки веб приложений с использованием языка php 5 и xml технологий, таких как xslt, xpath, xinclude. CompleXml бесплатен и имеет открытый исходный код, распространяется по лицензии new BSD

Требования

Для работы CompleXml требуется PHP >= 5.2.3, с поддержкой расширений libxml, xsl, xmlWriter, DOM/XML. Для работы с режиме командной строки необходимо расширение readline.

Установка и настройка CompleXml Framework

Для установки CompleXml необходимо скачать архив на сайте http://complexml.org или получите копию репозитория svn

svn co http://complexml.googlecode.com/svn/trunk complexml

после получения кода фрейморка, поместите содержимое директории lib/ в директорию, указаную в опции include_path ваших настроек php или добавте к настройкам этой опции путь к CompleXml в php.ini, так же возможна установка include_path перед выполнением скрипта, для этого перед каждым запуском скрипта выполняйте

set_include_path(get_include_path().PATH_SEPARATOR .'/path/to/CompleXml/lib');

Особенности и отличия

От аналогов CompleXml отличают ряд особенностей:

  • Производительный, расширяемый фреймворк
  • Построен на шаблоне проектирования MVC (Model - View - Controller), View часть фреймворка изолирована от модели и контролера за счет использования технологии XML+XSL.
  • Активное использование интроспекции языка для решения ряда задач
  • Гибкая система кеширования
  • Поддержка xsl преобразований в браузере пользователя.
  • "Честный" AJAX (asynchronous JavaScript + XML), ответы от сервера приходят в виде XML
  • Компоненты для работы с командной строкой, включая компоненты для создания многопоточных приложений

Начало работы

Создание проекта

Для быстрого начала работы с CompleXml, выполните команду из директории ./bin

./cx create project firstproject

Эта комманда создаст в текущем рабочем каталоге проект под названием firstproject, если вы хотите скопировать в lib директорию проекта копию фреймворка, выполните команду

./cx create project firstproject --with-lib

Для того, чтобы указать другую директорию, в которой нужно создать проект, используйте комманду:

./cx create project firstproject --dir /path/to/workspace

Примечание: в *NIX системах вы можете использовать команду alias для упрощения работы с командной строкой

alias cx=path/to/CompleXml/bin/cx

Структура проекта

После создания проекта, в рабочей директории создается проект, имеющий такую структуру:

./firstproject  #-->  корневая директория проекта (APPLICATION_HOME)
    application  #--> директория, с рабочими файлами проекта
      controllers  #--> контроллеры
        indexController.php  #--> файл, содержащий контроллер, срабатывающий по умолчанию
        errorController.php #--> файл, содержащий контроллер срабатывающий при ошибках
      configs #--> директория, для рабочей конфигурации проекта
      models #--> директория с моделями проекта
      ~locales #--> ссылка на директорию ./firstproject/public/locales, ссылка нужна для большей логичности структуры приложения, ее наличие не обязательно
      ~templates #--> ссылка на директорию ./firstproject/public/templates, ссылка нужна для большей логичности структуры приложения, ее наличие не обязательно
    cache #--> директория для кеша проекта 
    configs #--> глобальная конфигурация проекта
      main.ini.php  #--> файл основных настроек проекта
      cli.ini.php #--> файл настроек задач командной строки
    lib #--> директория, содержащая библиотеки проекта
    logs #--> директория журналов проекта
    public #--> DocumentRoot сервера
      templates #--> директория для шаблонов
        index 
          index.xsl
        error
          notfound.xsl
      locales #--> директория для локализаций
      index.php #--> DefaultIndex файл
      .htaccess
  cx #--> скрипт для управления проектом, для *NIX систем
  cx.php #--> php скрипт для управления проектом
  cx.bat #--> скрипт для управления проектом, для систем семейства windows
 

Примечание: ссылки на директории templates и locales в applications создаются только в *NIX системах

Для работы этого проекта, необходимо настроить веб сервер так, чтобы рабочая директория сервера (DocumentRoot) была направлена в firstproject/public

Настройка проекта

Конфигурация проекта находится в папке firstproject/configs, главный файл с настройки main.ini.php:

<?php

define('APPLICATION_HOME', dirname(dirname(__FILE__))); //путь к главной директории проекта

//добавляет к include_path, директории lib проекта
set_include_path(get_include_path().PATH_SEPARATOR.APPLICATION_HOME.DIRECTORY_SEPARATOR.'lib'); 

//подключает класс-загрузчик, который используется для подключения остальных классов фреймворка
require_once 'CompleXml/Loader.php'; 

//регистрирует autoload метод, при помощи которого автоматически подключаются остальные классы
spl_autoload_register(array('CompleXml_Loader', 'autoload'));

...

После определения константы APPLICATION_HOME, подключения загрузчика и установки autoload метода, можно установить свои параметры, для этого нужно использовать класс CompleXml_Config:

//установка массива параметров
CompleXml_Config::setArray(
     array(
        'foo'=>'bar',
        'test'=>'test'
     )
);

$foo = CompleXml_Config::get('foo'); //вернет "bar" 

//установка одиночного параметра 
CompleXml_Config::set('param', 'value'); 

Алгоритм обработки запроса

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

Рассмотрим как в CompleXml предлагается обрабатывать запрос от браузера пользователя и отдавать ответ.

Первым делом после получения запроса находится маршрутизатор (наследник CompleXml_Router) который соответствует параметрам запроса, для указания параметров в CompleXml используются DocBlock нотации. Для примера рассмотрим простой маршрутизатор, который создается вместе с проектом:

require_once '../configs/main.ini.php';

/**
 * параметр, указывающий фреймворку на домен, для которого 
 * предназначен этот маршрутизатор
 * @domain {enter your public domain}
 */
class PublicRouter extends CompleXml_Router
{
}

/**
 * для указания нескольких доменов, 
 * укажите несколько параметров @domain
 * @domain firstproject.dev
 * @domain www.firstproject.dev
 */
class DevRouter extends PublicRouter
{
    //метод вызывающийся после старта маршрутизатора 
    public function init()
    {
        CompleXml_Config::setSettings('Output_Xml',
            array('only_xml'=>$this->Request->getBool('xml'))
        );
    }
}

CompleXml_Application::run(); //запуск приложения

При обработке запроса, обработчик фреймворка CompleXml будет находить из всех объявленных наследников CompleXml_Router, выделение разных маршрутизаторов для разных доменов позволяет удобно и просто разделять логику работы для публичных, тестовых и серверов разработки. Если маршрутизатор не был найден, будет использоваться CompleXml_Router_Default.

Примечание: при поиске нужного маршрутизатора, первыми проверяются те, которые первые объявлены, это стоит учитывать при высоко нагруженных проектах, и объявлять раньше те маршрутизаторы, которые чаще вызываются и имеют более точные критерии в параметре @domain.

Примечание: поиск маршрутизатора происходит до первого объявленного маршрутизатора, удовлетворяющего условиям.

После нахождения маршрутизатора домена, происходит поиск метода-маршрута, который срабатывает на определенный @uri, в CompleXml_Router определен маршрут по умолчанию:

class CompleXml_Router{

  ...

    /**
     * @uri /
     * @uri /<controller:w>
     * @uri /<controller:w>/<action:w>
     */
    public function defaultRoute($controller, $action)
    {
        if (is_null($controller)){
            $controller = 'index';
        }
        if (is_null($action)){
            $action = 'index';
        }
        return array(
                    'controller'=>$controller, 
                    'action'=>$action
                    );
    }

   ...

}

Поиск маршрута происходит по параметру @uri в DocBlock методов маршрутизатора. После нахождения метода-маршрута, создается объект маршрутизатора, выполняется метод init() и выполняется метод-маршрут. Параметрами для маршрута могут быть переменные полученные из DocBlock аннотаций, например

    /**
     * @uri /<year:d>-<month:d>-<day:d>
     */
    public function myRoute( $year, $month, $day)
    {
       
        $controller = 'calendar';
        $action = 'show';
       
        return array(
                    'controller'=>$controller, 
                    'action'=>$action
                    );
    }

Порядок параметров метода не играет роли, важно что-бы имя параметра метода совпадало с переменной шаблона <year:d> - $year. Все найденные в аннотациях переменные будут доступны в объекте Request, объект Request объявлен в CompleXml_Router и доступен во всех маршрутизаторах:

    /**
     * @uri /<year:d>-<month:d>-<day:d>
     * пример произвольного порядка параметров в методе-маршруте
     */
    public function myRoute( $month, $day, $year)
    {
       
        $controller = 'calendar';
        $action = 'show';
        if ($year==$this->Request->getInt('year')){
               //код выполнится, так как все переменные из аннотаций попадают в $this->Request;
        }
        return array(
                    'controller'=>$controller, 
                    'action'=>$action
                    );
    }

Переменные аннотаций оформляются следующим образом <имя:тип>, в данный момент поддерживается 2 типа: w - любые буквенные символы и d - любые цифры.

Основная задача маршрутизатора - определить контролер и действие контролера, для того чтобы задать контроллер есть несколько способов это сделать - в параметре @uri можно задать шаблоны поиска переменных, например /<controller:w>/<action:w>; в методе-маршруте вернуть ассоциативный массив, содержащий 'controller' и 'action' значения; установить в объекте Request значения 'controller' и 'action', например

...
$this->Request->setValue('controller', 'index');
$this->Request->setValue('action', 'index');
...

Примечание: по умолчанию, маршрутизатор кешируется, если вы изменили маршрутизатор не забудьте выполнить команду для очистки кеша:

./cx cache clear

После того, как мы определились с контроллером и действием, начинается запуск контроллера, запуск происходит в несколько этапов:

  • Создание объекта контроллера
  • Инициализация View с которым будет работать контроллер
  • Вызов метода init()
  • Запуск обработчиков, которые вызываются до выполнения действия
  • Вызов метода-действия
  • Запуск обработчиков, которые вызываются после выполнения действия

Инициализация View заключается в указании необходимого шаблона и текущей локализации, путь к шаблону выглядит следующим образом: $controller.'/'.$action.'.xsl', для каждого контролера создается отдельный каталог, для каждого действия - отдельный файл шаблона

Отличительной особенностью запуска контроллера является наличие обработчиков до и после выполнения действий. За запуск обработчиков отвечают классы наследники CompleXml_Listener_Abstract. По умолчанию определен и вызывается CompleXml_Listener_Behaviour, в его задачи входит найти у метода действий аннотации @before и @after и выполнить у контроллера соответствующие методы

class indexController extends CompleXml_Controller{

    private $_time;
    
    //метод выполнится до indexAction()
    public function beforeIndex()
    {
        $this->_time = microtime(true);
    }
    
   /**
    * @before beforeIndex
    * @after afterIndex
    */
    public function indexAction()
    {
          //получение данных запроса
          $this->Request->getString('test');
          //получение данных сессии
          $this->Session->getString('test');
          //получение данных из куки
          $this->Cookies->getString('test');

    }
    
    //метод выполнится после indexAction()
    public function afterIndex()
    {
        $this->_time = microtime(true) - $this->_time; //время выполнения indexAction
    }
}

В контроллерах доступны объекты: Request - объект, для работы с данными запроса, передается в контроллер из маршрутизатора, экземпляр класса CompleXml_Dataset_Request; Response - объект для формирования ответа, экземпляр класса CompleXml_Router_Response; Session - объект для работы с сессиями, экземпляр класса CompleXml_Dataset_Session; Cookies - объект для работы с куками, экземпляр класса CompleXml_Dataset_Cookies; View - объект для работы с отображением, экземпляр класса CompleXml_View

После выполнения контроллера, запускаются классы, отдающие ответ - классы, реализующие интерфейс CompleXml_Output_Interface. В системе определены следующие выходные классы - CompleXml_Output_Xml, CompleXml_Output_Browser, CompleXml_Output_Xslt. Класс CompleXml_Output_Xml проверяет, что запрашиваются именно данные в XML формате и выдает их, для определения формата данных проверяется наличие заголовка X-Requested-With: XMLHttpRequest, такой заголовок устанавливают большинство javascript фреймворков при AJAX запросах, так же можно указать вручную XML формат ответа:

CompleXml_Config::setSettings('Output_Xml', array('only_xml'=>true));

CompleXml_Output_Browser проверяет есть ли возможность на стороне браузера делать xsl преобразование, проверка возможности преобразования происходит по значению User-Agent в заголовке запроса, в случае возможности преобразования, ответ отдается в виде XML с указанием шаблона для преобразования:

<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="/templates/index/index.xsl"?>
<page>
</page>

В данный момент поддерживаются браузеры: Opera > 9.0, Firefox > 3.0, Safari > 3.0, Chrome >1.0, Safari > 3.0 и Internet Explorer > 6.0. Вы можете указать свой набор браузеров в которых будет происходить преобразование на стороне браузера:

CompleXml_Config::setSettings('Output_Browser', array(
                  'xslt_browsers'=>array('Opera'=>10.0, 'Chrome'=>2.0, 'IE'=>8.0)
         );
);

CompleXml_Output_Xslt преобразовывает xml ответа при помощи xslt на стороне сервера и отдает браузеру результат.

Примечание: вы можете задать свои классы ответа

CompleXml_Config::setSettings('Application', array(
                  'outputs'=>array('CompleXml_Output_Xml', 'CompleXml_Output_Xslt') // конфигурация, позволяющая исключить браузерные преобразования xsl
         )
);

При указании классов ответа, важен порядок - после успешного выполнения класса ответа, следующие не запускаются. По умолчанию порядок вызова классов ответа: CompleXml_Output_Xml, CompleXml_Output_Browser, CompleXml_Output_Xslt.

Работа с View

Для работы с View частью приложения используется класс CompleXml_View, он наследуется через CompleXml_View_XmlWriter от класса XMLWriter. Класс CompleXml_View доступен во всех контроллерах приложения. Для передачи данных из модели в отображение можно воспользоваться несколькими методами класса CompleXml_View:

class controllerController extends CompleXml_Controller{

    public function actionAction()
    {
          $this->View->assign('test', 'test'); // создаст xml ветку <test>test</test>
          $this->View->assign('test'); // создаст xml ветку <controller-action>test</controller-action>
          $this->View->assign( // создаст xml ветку <controller-action><test>1</test></controller-action>
                          array('test'=>'1')
          );
          $this->View->writeElement('foo', 'bar'); // создаст xml ветку <foo>bar</foo>
          // следующий код создаст xml ветку <foo><![CDATA[bar]]></foo>
          $this->View->startElement('foo'); 
          $this->View->writeCData('bar');
          $this->View->endElement();

         $array = array('foo'=>'bar', 'test'=>'test');           
         $this->View->writeElement('ololo', $array); // создаст xml ветку <ololo><foo>bar</foo><test>test</test></ololo>
         $this->View->assign('ololo', $array); // создаст xml ветку <ololo><foo>bar</foo><test>test</test></ololo>
         $this->View->assign($array); // создаст xml ветку <controller-action><foo>bar</foo><test>test</test></controller-action>
    }    
}

В CompleXml шаблоны для представления данных из модели пишутся на xsl, шаблоны расположены в директории firstproject/public/templates, такое расположение обусловлено необходимостью иметь доступ к шаблонам при браузерной генерации страницы. При создании проекта создаются шаблоны для отображения первой страницы, для страницы ошибок и общий layout. Пример шаблона, генерируемого при создании проекта:

<?xml version="1.0" encoding="UTF-8"?>
<!-- шаблон для index страницы, файл firstproject/public/templates/index/index.xsl -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output encoding="UTF-8" method="html" omit-xml-declaration="yes" indent="no"
        doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
        doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>

    <xsl:include href="../layout.xsl" />

    <xsl:template match="/">
        <xsl:apply-templates select="page">
            <xsl:with-param name="title">Congratulations, CompleXml project started!</xsl:with-param>
        </xsl:apply-templates>
    </xsl:template>readComponent

    <xsl:template match="content">
       <h1>Congratulations, CompleXml project started!</h1>
       <p>for more informations visit <a href="http://complexml.org/docs" >documentation page</a></p> 
    </xsl:template>

</xsl:stylesheet>

Конфигурирование CompleXml Framework

Конфигурирование CompleXml framework построено на следующем принципе: каждый отдельный компонент может иметь свои предопределенные параметры конфигурации, они хранятся в директории ComleXmlData которая находится в директории lib фреймворка. Для получения данных о параметрах компонент воспользуйтесь CompleXml_Config:

//получение параметров CompleXml_Application
$settings = CompleXml_Config::readComponentSettings('CompleXml_Application');
//получение параметров CompleXml_Application, при получении параметров CompleXml_ можно не указывать
$settings = CompleXml_Config::readComponentSettings('Application');
//для получения конкретного параметра, можно воспользоваться
$models = CompleXml_Config::getSettings('Application', 'models');

Для переопределения параметров используйте все тот же CompleXml_Config:

//для получения конкретного параметра, можно воспользоваться
CompleXml_Config::setSettings('Application', array('models'=>'my_models'));

Для понимания того, что можно конфигурировать, рассмотрим параметры определенные в CompleXmlData, основные параметры приложения определены для CompleXml_Application:

//содержимое файла CompleXmlData/Application.php
return array(
    //путь к контролерам приложения
    'controllers'=> APPLICATION_HOME.
        DIRECTORY_SEPARATOR.'application'.DIRECTORY_SEPARATOR.'controllers',
    //путь к моделям
    'models' => APPLICATION_HOME.
        DIRECTORY_SEPARATOR.'application'.DIRECTORY_SEPARATOR.'models',
    //путь к директории настроек приложения
    'configs' => APPLICATION_HOME.
        DIRECTORY_SEPARATOR.'application'.DIRECTORY_SEPARATOR.'configs',
    //путь к журналам
    'logs'=> APPLICATION_HOME.
        DIRECTORY_SEPARATOR.'logs',
    //директория, в которую указывают настройки веб сервера
    'document_root'=>APPLICATION_HOME.
        DIRECTORY_SEPARATOR.'public',
    //путь к кешу приложения    
    'cache'=> APPLICATION_HOME.
        DIRECTORY_SEPARATOR.'cache',
    //драйвер для кеша
    'cache_driver'=> new CompleXml_Cache_Driver_File(array('dirname'=>APPLICATION_HOME.
        DIRECTORY_SEPARATOR.'cache')),
    //локаль по умолчанию
    'default_locale'=>'en_EN',
    //режим отладки
    'debug_mode'=>false,
    // кеширование маршрутизаторов
    'router_cache'=> true,
    //шаблон для имени контроллеров
    'controller_template'=> '%sController',
    //шаблон для имени метода-действия
    'action_template'=> '%sAction',
    //маршрутизатор по умолчанию
    'default_router'=> 'CompleXml_Router_Default',
    //метод-действие по умолчанию
    'default_action'=> 'index',
    //контроллер по умолчанию
    'default_controller'=> 'index',
    //слушатели событий
    'listeners' => array('CompleXml_Listener_Behaviour'),
    //классы ответа приложения
    'outputs' => array('CompleXml_Output_Xml', 'CompleXml_Output_Browser', 'CompleXml_Output_Xslt')
);

Параметры для CompleXml_View:

//содержимое файла CompleXmlData/View.php
return array(
    // главная ветка генерируемого xml документа
    'root'=>'page',
    // ветка xml, содержащая данные добавляемые из контролеров
    'content_node'=>'content'
);

Параметры для CompleXml_Cli:

//содержимое файла CompleXmlData/Cli.php
//задачи, выполняемые в режиме командной строки
$tasks = array('CompleXml_Cli_Task_Help','CompleXml_Cli_Task_Cache','CompleXml_Cli_Task_Create');
if (class_exists('Doctrine')||class_exists('Doctrine_Manager')){
//если подключена Doctrine, добавляется задача для работы с ORM Doctrine из командной строки
    $tasks[] = 'CompleXml_Cli_Task_Doctrine';
}
return array(
   //описание правил для анализа параметров командной строки
    'options' => array(
        '--task'=>array(
            'type'=>'String',
            'position'=>1
        ),
        '--action'=>array(
            'type'=>'String',
            'position'=>2
        )
    ),
    //слушатели событий
    'listeners' => array('CompleXml_Listener_Behaviour'),
    'tasks'=>$tasks
);

Параметры для CompleXml_Output_Browser:

//содержимое файла CompleXmlData/Output/Browser.php
return array(
    // сохраняет данные о браузере посетителя в сессию
    'with_get_browsers_cache'=> false,
    // список браузеров, поддерживающих xslt преобразования
    'xslt_browsers'=>
    array('Opera'=>9.0, 'Firefox'=>3.0, 'Safari'=>3.0, 'Chrome'=>1.0, 'IE'=>6.0, 'Safari'=>3.0),
    //путь к шаблонам
    'templates'=> '/templates',
    //путь к файлам локализации
    'locales'=> '/locales',
);

Параметры для CompleXml_Output_Xml:

//содержимое файла CompleXmlData/Output/Xml.php
//указывает на то, что данные нужны только в формате xml
return array('only_xml'=>false);

Параметры для CompleXml_Output_Xslt

//содержимое файла CompleXmlData/Output/Xslt.php
$CONFIG = array();
//путь к шаблонам, если шаблоны не доступны в директории проекта, то они берутся из document_root директории
if (file_exists(APPLICATION_HOME.DIRECTORY_SEPARATOR.'application'.DIRECTORY_SEPARATOR.'templates')){
    $CONFIG['templates'] = APPLICATION_HOME.DIRECTORY_SEPARATOR.'application'.DIRECTORY_SEPARATOR.'templates';
}else{
    $CONFIG['templates'] = CompleXml_Config::getSettings('Application', 'document_root').DIRECTORY_SEPARATOR.'templates';
}
//путь к файлам локализации, если файлы не доступны в директории проекта, то они берутся из document_root директории
if (file_exists(APPLICATION_HOME.DIRECTORY_SEPARATOR.'application'.DIRECTORY_SEPARATOR.'locales')){
    $CONFIG['locales'] = APPLICATION_HOME.DIRECTORY_SEPARATOR.'application'.DIRECTORY_SEPARATOR.'locales';
}else{
    $CONFIG['locales'] = CompleXml_Config::getSettings('Application', 'document_root').DIRECTORY_SEPARATOR.'locales';
}
return $CONFIG;

Работа с базами данных

CompleXml не навязывает конкретные инструменты для работы с базами данных. В CompleXml framework входит несколько классов для работы с БД: CompleXml_Db_Connection, CompleXml_Db_Doctrine.

CompleXml_Db_Connection наследник класса PDO, умеет логировать запросы при помощи CompleXml_Log, при сбоях возвращает исключение CompleXml_Db_Exception, может использоваться в разных ORM как соединение с базой данных.

//создание соединения
$connection = new CompleXml_Db_Connection('sqlite::memory:');

//выполнение запроса, $res - число затронутых полей
$res = $connection->exec('CREATE TABLE t(x INTEGER PRIMARY KEY DESC, y, z);'); // $res = 0
$res = $connection->exec('INSERT INTO t (x, y, z) VALUES (1, "111", 123);'); // $res = 1

//получение списка ответов
$resultArray = $connection->query('SELECT * FROM t')->fetchAll();

CompleXml framework легко интегрируется с ORM Doctrine, для подключения Doctrine в firstproject/configs/main.ini.php нужно добавить следующий код:

require_once('Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));

$doctrine_config = array(
    'data_fixtures_path'  =>  '/path/to/data_fixtures', 
    'models_path'         =>  CompleXml_Config::getSettings('Application', 'models'), //путь к моделям
    'migrations_path'     =>  '/path/to/migrations',
    'sql_path'            =>  '/path/to/sql',
    'yaml_schema_path'    =>  '/path/to/database_schema.yml',
    'connection'          => 'connections params or PDO object' //параметры соединения
);

Doctrine_Manager::getInstance()->setAttribute('autoload_table_classes', true);
Doctrine_Manager::getInstance()->setAttribute('model_loading', 'conservative');
Doctrine::loadModels($doctrine_config['models_path']);
Doctrine_Manager::connection($doctrine_config['connection']);

CompleXml_Config::set('doctrine_config', $doctrine_config);

Дополнительная информация о ORM Doctrine доступна по адресу http://www.doctrine-project.org/documentation.

CompleXml_Db_Doctrine - вспомогательный класс для работы с ORM Doctrine. Позволяет получать доступ к Doctrine_Pager как к массиву:

$currentPage = 1;
$resultsPerPage = 50;

$pager = new Doctrine_Pager(
      Doctrine_Query::create()
            ->from( 'User u' )
            ->leftJoin( 'u.Group g' )
            ->orderby( 'u.username ASC' ),
      $currentPage, 
      $resultsPerPage 
);
$result = $pager->execute();

$pagerArray = CompleXml_Db_Doctrine($pager);
//$pagerArray - массив данных о Doctrine_Pager, такой вид выгоднее отличается от простого объекта при создании xml.

Кеширование

CompleXml framework предоставляет простые и гибкие средства для кеширования. Идея кеширования в CompleXml состоит из таких понятий:

  • Драйверы кеширования - классы для работы с разными хранилищами данных, реализуют интерфейс CompleXml_Cache_Driver_Interface, доступны драйверы для Memcache, Apc, Xcache и File кеш.
  • Критерии кеширования - критерии по которым определяется актуальность данных в кеше, реализуют интерфейс CompleXml_Cache_Criteria_Interface, доступны критерии CompleXml_Cache_Criteria_Lifetime и CompleXml_Cache_Criteria_Tag
  • Менеджер кеша CompleXml_Cache

Пример работы с кешем:

//создание драйвера кеша
$cache_driver = new CompleXml_Cache_Driver_Xcache();

$cache = new CompleXml_Cache($cache_driver);

// установка кеша с временем жизни 50 секунд и двумя тегами 'tagA', 'tagB'
$cache->set('test', 'test', 50, array('tagA', 'tagB')); 

$val = $cache->get('test'); // $val == 'test';
// создание объекта критерия кеша
$cacheTagA = new CompleXml_Cache_Criteria_Tag($cache_driver, array('name'=>'tagA'));

// сброс кеша по критерию
$cacheTagA->flush();

$val = $cache->get('test'); // $val === false

// установка кеша с произвольными критериями
// установка кеша с временем жизни 100 секунд и двумя тегами 'tagX', 'tagZ'
$cache->set('test', 'test', false, false,
       array( 
         new CompleXml_Cache_Criteria_Lifetime($cache_driver, array('time'=>100)),
         new CompleXml_Cache_Criteria_Tag($cache_driver, array('name'=>'tagX')),
         new CompleXml_Cache_Criteria_Tag($cache_driver, array('name'=>'tagZ')),
     )
); 


Множества данных (Сессии, Куки, Request, POST, GET)

Для работы с массивами данных в CompleXml framework введен класс CompleXml_Dataset

Для работы множествами данных родительский класс CompleXml_Dataset содержит следующие методы:

  • getValue($name, $default = null, CompleXml_Validate_Abstract $validator = null) - метод возвращает данные из множества, в случае отсутствия данных отдает $default значение, $validator содержит класс, проверяющий данные перед отдачей, если данные не прошли проверку, отдается $default значение.
  • getString ($name, $default = null, $min_length = null, $max_length = null) — возвращает строку из множества, если длина строки не в пределах $minlength<=длина строки<= $maxlength, то возвращается $default значение.
  • getEmail ($name, $default = null) — возвращает данные из множества, если данные проходят проверку на e-mail.
  • getDomainName ($name, $default = null) возвращает данные из множества, если данные проходят проверку на доменное имя.
  • getInt ($name, $default = null, $min = null, $max = null) — возвращает целое число, если оно есть в множестве и находится в пределах от $min до $max
  • getBool ($name, $default = false) — возвращает булево значение данных из множества.
  • getAllValues () - возвращает массив всех значений
  • setValue($name, $value) — устанавливает значение в множество.
  • setValues($values) — устанавливает все значения.

Класс CompleXml_Dataset реализует интерфейсы Countable и Iterator,что позволяет работать с ним как с массивом.

CompleXml_Dataset_Request содержит данные о запросе, массив $_REQUEST и данные найденные в аннотациях маршрутизатора. У класса есть 3 публичных элемента - CompleXml_Dataset_Request->Post — объект CompleXml_Dataset содержащий $_POST, CompleXml_Dataset_Request->Get — объект CompleXml_Dataset содержащий $_GET, CompleXml_Dataset_Request->Uri — данные из строки запроса, разбитые по «/».

CompleXml_Dataset_Session содержит множество данных $_SESSION, в классе переопределен метод setValue(), при вызове этого метода, данные устанавливаются в сессию пользователя. Добавлены методы destroy() - уничтожает сессию и unregister($name) — удаляет переменную из сессии.

CompleXml_Dataset_Cookies содержит множество данных $_COOKIES, в классе переопределен метод setValue(), при вызове этого метода, данные устанавливаются в cookies пользователя.

Авторизация и права доступа

Для решения задач связаных с авторизацией и правами доступа в CompleXml предусмотренны модули CompleXml_Auth и CompleXml_Acl.

В модуль авторизации входит несколько классов: CompleXml_Auth - класс singleton который управляет авторизацией пользователя, CompleXml_Auth_Result - класс, хранящий информацию о авторизации и о авторизированом пользователе, CompleXml_Auth_Listener - класс наследник CompleXml_Listener_Abstarct, предназначен для определения доступности мотодов контролера авторизованым и неавторизованым пользователям.

Примеры работы с CompleXml_Auth:

//информация о пользователе, может быть любым типом данных
$user = array('id'=>1, 'name'=>'user');
//Авторизация пользователя
CompleXml_Auth::getInstance()->authenticate($user);

//проверка авторизации пользователя
if (CompleXml_Auth::getInstance()->isAuth()){
    //пользователь авторизирован
}else{
    //пользователь не авторизирован
}

//дата авторизации
$date = CompleXml_Auth::getInstance()->getDate();

//очистка информации о авторизированом пользователе
CompleXml_Auth::getInstance()->clearIdentity();

//установка информации о неудачной авторизации
CompleXml_Auth::getInstance()->brokenAuth();

//Установка ролей пользователя, роли необходимы для работы с правами доступа
CompleXml_Auth::getInstance()->addRole('admin');
CompleXml_Auth::getInstance()->addRole('editor');
CompleXml_Auth::getInstance()->setRoles(array('user1', 'user2'));

//Получение ролей пользователя
$roles = CompleXml_Auth::getInstance()->getRoles();
// Метод возвращает список ролей только в том случае, если пользователь авторизирован

// Очищает информацию о роляж пользователя
CompleXml_Auth::getInstance()->flushRoles();

Для работы с правами доступа в CompleXml используется модуль CompleXml_Acl, он состоит из следующих классов: CompleXml_Acl - класс для управления правами доступа, CompleXml_Acl_Role - класс, описывающий роль пользователя, CompleXml_Acl_Resource - класс, описывающий ресурс к которому будет проверяться доступ, CompleXml_Acl_Listener - наследник класса CompleXml_Listener_Abstract, предназначен для определения доступа к методам контролера в зависимости от ролей текущего пользователя.

Примеры использования CompleXml_Acl:

//Создание менеджера для управления правами доступа
$acl = new CompleXml_Acl();

//Создание роли
$role = new CompleXml_Acl_Role('role');

//Создание ресурса
$resource = new CompleXml_Acl_Resource('resource');

//Добавление роли к менеджеру acl
$acl->addRole($role);

//Добавление ресурса к менеджеру acl
$acl->addResource($resource);

//установка запрета для доступа к ресурсу resource для роли role
$acl->deny('resource', 'role');

if ($acl->isDeny('resource', 'role')){
   //проверка запрета для доступа к ресурсу
}

//установка разрешения доступа к ресурсу resource для роли role
$acl->allow('resource', 'role');

if ($acl->isAllow('resource', 'role')){
   //проверка разрешения доступа к ресурсу
}

Пример контролера с использованием CompleXml_Auth и CompleXml_Acl:

class exampleController extends CompleXml_Controller
{
    /**
     * Метод доступен для всех пользователей
     */
    public function loginAction()
    {
        $name = $this->Request->Post->getString('name');
        $password = $this->Request->Post->getString('password');

        if (($name=='name')&&($password=='password')){
            CompleXml_Auth::getInstance()->authenticate(array('name'=>$name));
            CompleXml_Auth::getInstance()->addRole('user');
        }
        if (($name=='admin')&&($password=='adminpassword')){
            CompleXml_Auth::getInstance()->authenticate(array('name'=>$name));
            CompleXml_Auth::getInstance()->addRole('admin');
        }
    }

    /**
     * Метод secretAction доступен только для авторизированных пользователей
     * @auth true
     */
    public function secretAction()
    {
        
    }
    /**
     * Метод adminAction доступен только для авторизированных пользователей
     * с ролью admin
     * @allow admin
     */
    public function adminAction()
    {
        
    }
    /**
     * Метод danyUserAction доступен только для авторизированных пользователей
     * с ролью оличной от user
     * @deny user
     */
    public function denyUserAction()
    {

    }
}

Примечание: для работы с анотациями @auth, @allow и @dany необходимы подключенные классы CompleXml_Auth_Listener и CompleXml_Acl_Listener, которые по умолчанию не подключены, для подключения необходимо выполнить код:

CompleXml_Config::setSettings('Application', 
    array('listeners' => array('CompleXml_Auth_Listener', 'CompleXml_Acl_Listener'))
);

Ведение журналов (Logs)

Для ведения журналов в системе предназначен модуль CompleXml_Log, его особенностью является то, что процесс журналирования происходит через статические методы, что позволяет уменьшить используемую память и ускорить ведения журналов. Ведение журналов можно разделить на три этапа: запись, форматирование и фильтрация журналов. За запись журналов отвечают классы-наследники CompleXml_Log_Writer_Abstract, за форматирование - CompleXml_Log_Format_Abstract и за фильтрацию данных для журналов ComleXml_Log_Filter_Abstract.

Методы модуля: - CompleXml::add ($message, $type) — добавление записи в журнал - CompleXml::addWriter (CompleXml_Log_Writer_Abstract $writer) — добавление потока сохранения журнала. Типы сообщений журналирования в порядке убывания приоритета:

const EMERG = 0;
const ALERT = 1;
const CRIT = 2;
const ERR = 3;
const WARN = 4;
const NOTICE = 5;
const INFO = 6;
const DEBUG = 7; 

Пример использования CompleXml_Log

    // создание класса, записывающего журнал
    $writer = new CompleXml_Log_Writer_Stream('/var/logs/complexml.log');
    
    // установка формата записей в журнале
    $writer->setFormat(new CompleXml_Log_Format_Simple());
    
    // установка фильтра журнала по типу сообщения
    $types = array(CompleXml_Log::ERR, CompleXml_Log::DEBUG);
    $writer->addFilter(new CompleXml_Log_Filter_Type($types));

    CompleXml_Log::addWriter($writer);

    CompleXml_Log::add('Debug message', CompleXml_Log::DEBUG); // сообщение будет записано в журнал

    CompleXml_Log::add('Info message', CompleXml_Log::INFO); // сообщение не будет записано в журнал

Производительность

Одним из преимуществ CompleXml framework является его высокая производительность, в качестве доказательств здесь приведены сравнительный тесты производительности с такими известными фреймворками как Zend Framework 1.9.3PL1, symfony 1.2.9 и позиционирующем себя как самый быстрый фреймворк Yii 1.0.10.r1472.

Как проводились тесты, на сайтах фреймворков были получены их свежие версии, в документациях по руководствам быстрый старт, развернуты типичные проекты, в настройках apache созданы виртуальные хосты под каждый проект, далее на каждый виртуальный хост выполнялась команда:

ab -t 30 -c 10 {имя хоста}

После выполнения команды, веб сервер перегружался. Количество вызовов функций измерялось при помощи Xdebug's Profiler.

Оборудование и программное обеспечение:

Processor:	          AMD Turion(tm) 64 Mobile Technology ML-37(2GHz)
Memory:	                  2060MB 
Operating System:	  Ubuntu 9.10

Server version: Apache/2.2.12 (Ubuntu)

PHP 5.2.10-2ubuntu6.1 with Suhosin-Patch 0.9.7 (cli) (built: Oct 29 2009 19:28:39) 
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
    with XCache v1.2.2, Copyright (c) 2005-2007, by mOo
    with Xdebug v2.0.4, Copyright (c) 2002-2008, by Derick Rethans

Сводная таблица:

&nbsp; Всего запросов Запросов в секунду Передано данных(байт) Вызовов функций
CompleXml 0.3.1 509 16,97 545648 168
CompleXml 0.3.1 (только XML ответ) 856 28,52 466520 128
Zend Framework 1.9.3PL1 222 7,39 278832 406
Symfony 1.2.9 149 4,91 347700 495
Yii 1.0.10.r1472 424 14,11 1503080 271
requests requests per second bytes functions calls