суббота, 31 декабря 2011 г.

Шаблоны

Шаблон отображается или назначается из контроллера следующим методом
base_controller->template(template, params, return)
template — название шаблона
params — параметры шаблона (массив), в шаблоне элементы массива станивятся переменными.
return:
return === true: метод возвращает шаблон как строку
return === false: шаблон будет встроен в др. шаблоны в переменной $template_template (по умолчанию)
return строка: шаблон будет встроен в др. шаблоны в переменной $template_return

Дополнения

Модуль ошибок
Модуль используется фр. для вывода ошибок, находится в директории core/errors.php
Основные виды ошибок
class rc_Exception extends Exception
 - Класс, кот. используется по умолчанию для вывода ошибок
class rcException extends Exception
 - Базовый класс для вывода ошибок
class dbException extends rcException
 - Класс для вывода ошибок при работе с базой данных (используется в классе db и всех его методах)
class routingException extends rc_Exception
 - Класс для вывода ошибок маршрутизации (используется в базовом контроллере - base_front_controller)
Пример:
Throw new rcException('Test Exception');
Throw new dbException("DB error", "SELECT id, ip, key, data FROM session WHERE 1");

Класс для вывода данных
Используется в модуле ошибок, находится в директории core/output.php
Основной метод:
output::show($data)
$data - Данные для вывода, формат данных определяется автоматически
Свойства (статические) класса output
public static $return = false;
  - возвращать ли отформатированные данные методом output::show()
public static $delimiter = ' => ';
 - Разделитель используемый для вывода данных (если данные - массив)
public static $show_index = true;
 - Показывать ли индекс массива при выводе данных (если данные - массив)

пятница, 30 декабря 2011 г.

Проверка входных данных

Класс для проверки входных данных предназначем для проверки произвольных данных на соответствие зпданным условиям. Он может использоваться для проверки форм как дополнительный инструмент (фаза проверки на стороне сервера).
При этом я заранее предполагаю, что "полноценная проверка" будет проводится на стороне клиента.
Создание класса
$check = new check('check/test_check', 'en', true);
  check/test_check - Нахождение файла настроек (config/check/test_check.php)
  en - локаль (для проверки дат и других региональных данных)
  true - проверять ли все входные данные. Если проверяются не все данные (значение false) - ф-я check() возвращает значение true или false. Если проверяеются все данные - ф-я check() за место false возвращает массив значений "array(field => return_value, ...)". 

Проверка осуществляется ф-ей check():
$res = $check->check($input_data);

  $input_data - входные данные



Стандартные ф-и проверки
  function not_empty($value)
   - Проверка на пустое значение 
  function is_equal($value, $eq_value)
   - Проверка на  равенство значению
  function is_array($value)
   - Является ли массивом
  function is_float($value)
   - Является ли числом дробным
  function is_int($value)
   - Является ли числом целым
  function is_num($value)
   - Является ли числом
  function value_between($value, $min, $max)
   - Значение в границах диапазона
  function value_less($value, $max)
   - Значение меньше чем
  function length_greater($value, $min)
   - Значение больше чем
  function is_url($value)
   - Является ли URL
  function is_email($value)
   - Является ли EMAIL
  function is_date($value)
   - Является датой ли (используются региональные настройки)
  function is_time($value)
   - Является ли временем (используются региональные настройки)
  function is_datetime($value)
   - Является ли датовременем (используются региональные настройки)
Дополнительные проверки
Дополнительное поле добавляется ф-ей add_rule
add_rule('название поля', $lambda_function, "Сообщение при ошибке'");
 - $lambda_function лямбда - функция (PHP 5.3+) возвращаемое значение: true/false
Файл настроек
Файл настроек класса check является стандартным файлом настроек, значения индексов являются массивом из трёх элементов:
1)Название ф-и проверки
2)Дополнительный параметр (если д.п. является другое поле, тогда оно обозначается следующим образом: '@@название_поля'). Параметр опциональный.
3)Возвращаемое значение при ошибке. Если не указано - возвращается false. Параметр опциональный.
 * Названия полей могут иметь префиксы (_) в начале и конце (чтобы можно было повесить несколько проверок на одно поле)

Пример файла настроек:
<?php
$form = array(
'email' => array('not_empty', '', 'email is emty'),
'email_' => array('is_email', '', 'email is not email'),
'pass' => array('not_empty', '', 'password is emty'),
'pass_' => array('length_greater', 4, 'password must be greater than 4 characters'),
'pass_confirm' => array('is_equal', '@@pass', 'Passwords does not match'),
'phone' => array('not_empty', '', 'phone is emty'),
'phone_' => array('length_greater', 4, 'phone must be greater than 4 characters'),
'firstname' => array('not_empty', '', 'firstname is emty'),
'firstname_' => array('length_greater', 4, 'firstname must be greater than 4 characters'),
'secondname' => array('not_empty', '', 'secondname is emty'),
'secondname_' => array('length_greater', 4, 'secondname must be greater than 4 characters'),
'bdate' => array('not_empty', '', 'Birthdate is emty'),
'bdate_' => array('is_date', '', 'Birthdate is not date'),
'address' => array('not_empty', '', 'address is emty'),
  'address_' => array('length_greater', 9, 'address must be greater than 9 characters')
);
?>


Пример:
if(count($_POST) > 0) {
    $check = new check('check/test_check, 'en', true);
    $function = function($custom) { return( $custom == 'qwerty' ); };
    $check->add_rule('custom', $function, "Value must be equal 'qwerty'");
    $res = $check->check($_POST);
    if($res === true) {
        print "Check OK";
    }
    else {
        print print_r($res); 
    }
}

понедельник, 26 декабря 2011 г.

Маршрутизация

RC изпользует модуль apache mod_rewrite и файл .htaccess
Маршрутизацию обеспечивает главный контроллер - front controller
Настройка маршрутизации находится в файле config/routes.php
Зпуск главного контроллера
$front = new frontController($role);
$front->run();

$role - опционально, роль юзера, по умолчанию 'guest'
Главный контроллер
function run() {
  //Запустить соотв. контроллер 
  $this->runControllers();
  //Отобразить главный шаблон (здесь исп. шаблон 'main')
  $this->display('main');
}

onRunController($conroller, $method, &$params, $allow_users, &$continue)
Событие выполняющееся перед запуском контроллера
$conroller - название контроллера
$method - запускаемый метод
$params - передаваемые параметры
$allow_users - разрешенно юзерам - список (массив) ролей
$continue - запускать ли контроллер
Файл настроек
Индекс явлеется регулярным выражением
$routes['route/<:num>/([0-9]+)'] = 'controller.method.x=y'
Пддерживаются следующие параметры <:num> - номер <:string> - строка (без спецсимволов) <:text> - строка
Значение: контроллер.метод.индекс=значение ....

Параметры передаваемые контролеру:
числовой индекс (0,1,2,3,4,5) - Regex mathes
  строковой индекс — (q=qwerty.x=y) — пары значений разделённые символами (.)
Маршруты по умолчанию
$routes['@default']: если пустой URL маршрут
$routes['@error']: путь не найден
$routes['@denied']: доступ юзеру запрещён

Доступ
по умолчанию: доступ для всех юзеров (или .allow=*)
.allow=user: доступ только юзеру с ролью «user,» иначе перенаправить на $routes['@denied']

Пример:
$routes['main/admin'] =
'admin.index.module=admin.url=/main/admin.allow=admin.param_x=xxx';

$routes['orders/edit/<:num>'] =
'orders.edit.module=orders.url=/orders/edit/.allow=user';

Работа с БД (Simple SQL)

Каждая модель (класс base_model) обладает методами раблты с БД:
UPDATE, INSERT, DELETE
//создание модели
$test = new test(); 
//Вставка записи
$test->insert(array('t1' => 't1', 't2' => 't2', 't3' => 't3', 't4' => 't4'));
//Редактирование записи
$test->update(
    array('t1' => 't1', 't2' => 't22', 't3' => 't333', 't4' => 't4444'),
    array('t1' => 't1', 't2' => 't2', 't3' => 't3', 't4' => 't4')
);

1й парраметр — данные
2й параметр — условие (массив или строка)
//Удаление записи
$test->delete(
    array('t1' => 't1', 't2' => 't22', 't3' => 't333', 't4' => 't4444')
);

Единственный параметр - условие (массив или строка)

SELECT
$test->select_condition_result(fields, condition, [order_by], [limit_from], [limit_offset])

condition: условие
 - c массив или строка
- pk значение первичного ключа 
result: возвращаемое значение
 - a массив строк
 - l массив ( array('field1' => 'field2', ....) )
 - r первая строка
 - v значение

fields — поля (массив или строка)
condition — условие (массив или строка)
order_by — порядок сортировки (например «name asc, date desc») (опционально)
limit_from - число (опционально)
limit_offset - число (опционально)

Примеры:
$test->select_pk_a("*", '1')
$test->select_c_a("*", '1')
$test->select_c_v("*", array("t4" => "rty"))
$test->select_c_v("*", array("t4" => "rty"), "t1 ASC, t2 DESC", 0, 10)

Функции класса db
db::escapeValue($value): экранировать значение
db::getList($sql): вернуть результат запроса в виде массива ( array('field1' => 'field2', ....) )
db::getResult($sql): вернуть результат запроса - первую строку
db::getValue($sql): вернуть результат запроса - значение
db::getLastId($table): .......
db::getQuery(sql): вернуть результат запроса - массив строк
db::execQuery(sql): выполнить запрос

Региональные настройки

Загрузка региональных настроек по-умолчанию
//Локаль 'en'
load_config('regional', array('default_locale' => 'en'));
Региональные функции
//Является ли $date датой, $locale - используемая локаль (опционально, по умолчанию 'en')
function is_date($date, $locale = '')
//Является ли $time временем, $locale - используемая локаль (опционально)
function is_time($time, $locale = '')
//Является ли $datetime датовременем, $locale - используемая локаль (опционально)
function is_datetime($datetime, $locale = '')

//Конвертировать дату из одной локали в другую
date_convert($from_locale, $to_locale, $date)
//Конвертировать время (часы и минуты) из одной локали в другую
time_convert($from_locale, $to_locale, $time)
//Конвертировать время (часы минуты секунды) из одной локали в другую
time_convert_full($from_locale, $to_locale, $time)
//Конвертировать датовремя (дата часы минуты) из одной локали в другую
datetime_convert($from_locale, $to_locale, $datetime)
//Конвертировать датовремя (дата часы минуты секунды) из одной локали в другую
datetime_convert_full($from_locale, $to_locale, $datetime)

Структура регионального файла

<?php
//Формат даты в регулярном выражении
$en['date_format_regex'] = "([\d]{2})\/([\d]{2})\/([\d]{4})";
//Формат времени в регулярном выражении
$en['time_format_regex'] = "([\d]{2}):([\d]{2}):{0,1}([\d]{0,2})";
//Формат датовремени в регулярном выражении
$en['date_time_format_regex'] = "$en[date_format_regex][\s]+$en[time_format_regex]";

//Индекс дня в регулярном выражении даты
$en['date_format_day_order'] = 2;
//Индекс месяца в регулярном выражении даты
$en['date_format_month_order'] = 1;
//Индекс года в регулярном выражении даты
$en['date_format_year_order'] = 3;
//Индекс часа в регулярном выражении времени
$en['time_format_hour_order'] = 1;
//Индекс минуты в регулярном выражении времени
$en['time_format_minute_order'] = 2;
//Индекс дня в регулярном выражении времени
$en['time_format_second_order'] = 3;

//Формат даты
$en['date_format'] = "<:month>/<:day>/<:year>";
//Формат времени
$en['time_format'] = "<:hour>:<:minute>";
//Формат времени (полный + секунды)
$en['time_format_full'] = "<:hour>:<:minute>:<:second>";
//Формат датовремени 
$en['date_time_format'] = "$en[date_format] $en[time_format]";
//Формат датовремени (полный + секунды)
$en['date_time_format_full'] = "$en[date_format] $en[time_format_full]";
?>


Настройки всех локалей находятся в каталоге "config/regional"

воскресенье, 25 декабря 2011 г.

Модуль настроек

Все настройки находятся в директории "protected/config"

[admin] — конфигурация административного модуля
[check] — настройки проверки форм (если загружен модуль)
[autoload.php] — здесь находятся директории, из которых будут автоматически загружатся классы
[config.php] — общие настройки (development/online, show errors)
[db.php] — Настройки базы данных (PDO)  (если загружен модуль)
[path.php] — нахождение важных системных папок
[regional.php] — региональные настройки
[routes.php] — связь маршрута URL и контроллеров (подробнее в комментариях файла) (используется в главном контроллере - front controller)
[tables.php] — псевдонимы таблиц (используется в классе db)

Функции модуля настроек


function load_config($module_path, $params = '')
 - Загрузить настройки из файла с параметрами
$module_path — путь к файлу настройки, например
$params - параметры (опционально)
(!) Элементы массива параметров (
$params) в файле настроек становятся переменными, при этом эти параметры используются во всех последующих загружаемых файлах настроек
(!) Если файл конфигурации не загружен, он инклудится средствами ПХП, иначе ничего не происходит (т.е. файл загружается 1 раз).
(!) Если например мы загрузили файл настроек test1 (load_config('test1')) - тогда массив test1 во всех последующих настроечных файлах превращается в переменную test1, содержимое которой равно содержимому массива test1 из файла test1.

Примеры:
load_config('x1') — загрузить массив конфигурации из файла config/x1.php
load_config('xxx/yyy') — загрузить массив конфигурации из файла config/xxx/yyy.php
load_config('regional', array('default_locale' => 'ru')) — загрузить файл конфигурации regional/config.php, значение переменной $default_locale в файле будет равна 'ru'

function get_config($config_path)

 - Вернуть массив конфигурации, либо любое значение его индекса неограниченной вложенности.
(!) Если файл конфигурации не загружен, он инклудится средствами ПХП, иначе возвращается уже загруженный модуль (т.е. файл загружается 1 раз).

(!) Если например мы загрузили файл настроек test1 (get_config('test1')) - тогда массив test1 во всех последующих настроечных файлах превращается в переменную test1, содержимое которой равно содержимому массива test1 из файла test1.

Примеры:
get_config('config') — вернуть массив конфигурации из файла config/config.php
get_config('xxx/yyy') — вернуть массив конфигурации из файла config/xxx/yyy.php
get_config('config.DEBUG_MODE') — вернуть значение ключа DEBUG_MODE из массива конфигурации из файла config/config.php

function delete_config($module)
- выгрузить заранее загруженный модуль конфигурации


Пример:


config/text1.php

<?php
$test1['hello'] = ' -=HELLO FROM TEST '.$number.'=- ';
?>



config/test2.php

<?php
$test2['xyz'] = array(
  'x' => 'test2: '.$test1['hello']
);
?>



//Somewher in code ...
load_config('test1', array('number' => '1'));
$x = get_config('test2.xyz.x');
echo $x;

Выведет:
test2: -=HELLO FROM TEST 111=-

Первая запись

Приветствую!
Решил написать систему на движке PHP ...
Система называется RC - rewrite and customize - переписывай и настраивай, т.е. с этим нет никаких проблем :)

Зачем и для кого?
В первую очередь для себя. Все остальные фреймворки отличаются своей сложностью, на освоение нового фр. тратится огромное кол-во времени + если хочешь сделать что-то нестандартное или нешаблонное натыкаешься на тупик. Поэтому, я попыталься создать что-то простое, что можно с лёгкостью настроить "под себя". Мой фреймворк не ставит перед собой цель "переплюнуть" таких "мостров" как Zend и Symfony, однако может стать основой для другого фреймворка.
В своё время я написал пару вещей на CodeIgniter , мне этот фр. понравился своей простотой, но тем не менее я понял, как можно сделать лучше некоторые вещи (файлы настроек, автозагрузка классов, маршрутизация и т.д.)

Структура:
Основной класс называется rc , также он является статичным, он отвечает за автозагрузку классов и управление настройками, всё остальное загружается опционально. Класс rc после инициализации загружает стартовый скрипт (по умолчанию run.php в корневой директории фреймворка) (это делается опционально, т.к. фр. может работать и запускаться из одного файла)
FrontController - главный контроллер, он отвечает за маршрутизацию.
Как и в любой архитектуре MVC контроллер загружает модели и отображает шаблоны. При этом используется "децентрализованная система шаблонов", а именно любой шаблон может быть встроен в любое место другого шаблона. Отображается один едиственный главный шаблон в главном контроллере, все остальные шаблоны в него "встраиваются".

Основные нововведения:
1)Файлы настроек:
   Все настройки хранятся в файлах .php в формате стандартного массива.
Почему не XML, JAML, INI ... ?
В файле настроек можно написать код, кот. будет загружать настройки из другого места, в т.ч. из (XML, JAML, INI). Также в файл настроек можно передавать параметры в т.ч. из других настроечных файлов.
2)Региональные настройки
   Региональные настройки обеспечивают поддержку мультиязычности на уровне дат и прочих форматов, хранятся настройки в отдельных файлах в директории "config/regional". Есть возможность конвертировать даты и др. форматы из одной региональной локали в другую. При этом локаль не обязательно язык, она может быть просто определённым форматом данных (например MySQL, MsSQL).
3)Библиотека "Simple SQL"
    Я являюсь противником паттерна "ActiveRecord" и прочих "конструкторов SQL", если в запросе используется больше, чем одна таблица - его лучше писать в ручную. Библиотека "Simple SQL" реализует простые запросы (SELECT, UPDATE, INSERT, DELETE) при помощью одной ф-и и параметров.
4)Маршрутизация
   Маршрутизация настраивается в отдельной файле настроек "config/routes.php", при этом можно указывать дополнительные параметры, кот. будут передаватся в контроллер.

В следующих постах подробнее распишу 1 2 3 и 4

С новым годом!

Ссылко на гитхаб