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

Изменения и Дополнения

Прошёл почти год, RC был использован во многих проектах, было много изменений, была практически написана новая версия.
А именно:
Событийная модель  была переписана с использованием лямбда ф-ий, также лямбды используются в классе кеширования, для которого теперь можно написать любой модуль, как для работы с файлами, так и с memcached и вообще чем угодно ...
Шаблоны выведены в отдельный класс.
Введена полная поддержка REST

Сорцы находятся здесь

CACHE

Инициализация и настройка

CACHE::init('frontend');
CACHE::$enabled = true;

/* rc/config/cache.php */
$cache = array(
    'modules' => array(
      'frontend' => array(
        'enabled' => false,
        'adapter' => 'Files'
      )
    ),

'classes' => array(
    '1min' => 60,
    '5min' => 300,
    '10min' => 600,
    '30min' => 1800,
    '1h' => 3600,
    '2h' => 7200,
    '6h' => 3600*6,
    '12h' => 3600*12,
    '24h' => 3600*24
    )
);

В шаблоне

<? if(CACHE::start('cache for 24 hours, '24h')): ?>
      HTML <?php  echo 'php';  ?>
<? endif; CACHE::end(); ?>

В моделях и контроллерах

$fff = function () use ($id, $place_id) {
    $e = new events();
    $p = new places();
    $event_item = $e->get($id, url::$lang);
    $event_item['place'] = $p->get($place_id, url::$lang);
    return $event_item;
};


$event_item = CACHE::process("EVENTS-show $place_id $id", '30min', $fff);

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


function register($params) {
    $tparams = array();
    if(isset($_POST['email'])) {
      $data = array('email' => $_POST['email'], 'pass' =>  md5($_POST['pass']));
      if($user_id = USER::register($data)) {
        USER::force_login($user_id);
        redirect::go ('/'.USER::get_field('email'));
      }
      else {
        $tparams['err'] = 'Internal error';
      }
    }
    VIEW::template('register', $tparams, 'content');
    VIEW::display('main', array('method' => 'register'));

}

Event manager

events::on('event',
    function($param) {
      echo "The event has been triggered with param '$param'";
    });
//...
events::trigger('event', 'xxx');

USER class

USER::init(new userAdapterDB(new users()));
//...
if($user_id = USER::register($data)) {
    USER::force_login($user_id);
    redirect::go ('/'.USER::get_field('email'));
}

if(USER::login($_POST['email'], $_POST['pass']))
    redirect::go ('/'.USER::get_field('email'));

$user_id = USER::get_pk();

/*   rc/lib/USER/adapters/DB.php   */

public function login($email, $password) {
  //...
}

public function register($data) {
    $this->user_model->insert($data);
    return $this->user_model->get_last_id();
}

REST

$routes['todo/<:num>']['?GET'] = 'todos.get_item';
$routes['todo/<:num>']['?PUT'] = 'todos.edit';
$routes['todo']['?POST'] = 'todos.add';
$routes['todo/<:num>']['?DELETE'] = 'todos.del';


четверг, 5 января 2012 г.

Дополнения

Событийная Модель
Всё это добро я назвал EventManager, реализует паттерн observer и позволяетсоздавать события в разных местах фр., но в тоже время обрабатывать их (события) в одном определённом месте - папка protected/events. В этой папке находятся обозреватели (observers), они загружаются автоматически (средствами PHP). Каждый класс обозревателя имеет суффикс Observer (например testObserver), каждый такой класс наследуется от класса Observer . Название метода совпадает с названием события.

Запуск события осуществляется ф-ей:
function trigger_event($slot, $event, &$params)
$slot - слот событий
$event - название события
$params - параметры, передаваемые ссылкой

Например, если сработало событие trigger_event('test', "test_event", $params); , тогда в папке protected/events в файле test.php в классе class testObserver сработает метод test_event .

class testObserver extends Observer {
    public function test_event(&$params) {
      //....     
      $params['1'] = 'New param value';
    }
}

Это был обозреватель по умолчанию, также можно назначить сколько угодно пользовательских обозревателей (унаследованных от customObserver), при этом нужно соблюдать 2 условия:
1)Избегать конфликта имён классов
2)Обозреватель должен быть создан до срабатывания события

class test_observer extends customObserver {
  public function test_event(&$params) {
    print "Inside custom observer";
    $params['x'] = '
New param value';
  }
}
CACHE
Написал небольшой, простенький модуль для кеширования
cache::start(); - начать кеширование
public static function start($time = 10, $name = '')
  $time - промежуток кеширования (секунды)
  $name - название файла для кеша (по умолчанию - хеш из URL)
cache::end(); - закончить кеширование
Запускается всё это дело из frontController
Файлы хранятся в папке protected/cache

Ещё один вариант использования класса cache:

//Проверяем, закеширован ли 'translate',
//а также возраст кеша - меньше часа
if(cache::cache_exists_time('translate', 3600)) {
    //Загружаем
    $translate = cache::cache_load('translate');
}
else {

    //Загружаем данные в переменную $translate обычным способом
    //...

    //Сохраняем кеш
    cache::cache_save('translate', $translate);
}

суббота, 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 = ' =&gt; ';
 - Разделитель используемый для вывода данных (если данные - массив)
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): выполнить запрос