SOM. (Simple Object Manipulation)

Общие сведения

SOM (Simple Object Manipulation) - это простая ORM, позволяющая работать с записями в базе данных посредством моделей, объектов, обладающих определенным набором методов, свойств и связями с другими моделями.

SOM является логическим продолжением ORM из cot-factory и представляет собой усовершенствованную и доработанную ORM из упомянутой библиотеки. Спасибо Gert Hengeveld и Владимиру Сибирову (trastmaster) за их труд над cot-factory.

 

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

 

Требования

Для правильной работы необходим php не ниже версии 5.3

 

Использование нескольких соединений с бд

Иногда бывает необходимо использовать несколько соединений с базой данных. Например когда Вы используете данные, которые хранятся в разных БД или пишите конвертер для переноса данных из одной БД в другую. SOM предоставляет Вам такую возможность.

Для этого в файл datas/config.php вашего сайта добавте описание нужных соединений:

$cfg['db_connect_name'] = array(
      'adapter' => 'mysql',   // 'pgsql' or 'mongo'
      'host' => '127.0.0.1',
      'port' => null,
      'username' => '12345',
      'password' => '6789',
      'dbname' => 'my_data_base',
 );

Поддерживаются базы данных MySql и PostgreSQL. Mongo - эксперементально.

Чтобы установить соединение вызовите фабричный метод:

$db_my_conn = Som::getAdapter('db_connect_name');

который вернет объект Som_Model_Mapper нужного типа. После этого можно отправлять ему запросы обычным образом:

$db_my_conn->query("SELECT * FROM `cot_some_table` ORDER BY id ASC");

Также Вы можете передавать имена соединений моделям при инициализации, если необходимо использовать соединения, отличные от системного в Cotonti.

Соединения кешируются на период выполнения. Это значит, что Вы можете вызывать метод Som::getAdapter с одним и тем же параметром столько - сколько Вам нужно. Объект соединения с БД не будет создаваться каждый раз заново, а будет возвращаться ссылка на один раз созданный объект.

 

Создание моделей

Конкретная модель создается классом, который наследуется от класса Som_Model_Abstract. Соотвественно, он насследует все его методы. В создаваемом классе модели обязательно должны быть определены следующие свойства:

protected static $_db;
protected static $_tbname = 'katalogshop_sale';

и опционально

protected static $_primary_key = 'prod_id';

$_db хранит ссылку на объект базы данных
$_tbname - имя таблицы в БД. Указывается явно при объявлении.
$_primary_key - название поля - первичный ключ таблицы. Если не указано, то используется поле 'id'.

В конце файла класса модели необходимо вызвать статический метод этого класса _init(). По умолчанию будет выполнен соотвествующий метод родительского класса. Это т.н. «статический конструктор», который выполняет начальную инициализацию модели, заполняет свойства $_db и загружает экстраполя.
 

пример модели расписания для группы ВУЗА:

<?php
defined('COT_CODE') or die('Wrong URL.');

/**
 * Модель Schedule
 *
 * Расписание
 *
 * @method static vuz_model_Schedule getById($pk);
 * @method static vuz_model_Schedule fetchOne($conditions = array(), $order = '');
 * @method static vuz_model_Schedule[] find($conditions = array(), $limit = 0, $offset = 0, $order = '');
 *
 * @property int    $id
 * @property string $title         Заголовок
 * @property string $description   Описание
 * @property string $text          Текст
 * @property string $begin         Дата начала
 * @property string $end           Дата окончания
 * @property string $created       Дата создания
 * @property string $created_by    Кем создано
 * @property string $updated       Дата обновления
 * @property string $updated_by    Кем обновлено
 *
 * @property vuz_model_Group $sgroup
 *
 * @property string $displayTitle
 */
class vuz_model_Schedule extends Som_Model_Abstract
{
    /**
     * @var Som_Model_Mapper_Abstract
     */
    protected  static $_db = null;
    protected  static $_tbname = '';
    protected  static $_primary_key = 'id';

    /**
     * Static constructor
     */
    public static function __init($db = 'db'){
        global $db_soc_groups_schedule;

        static::$_tbname = $db_soc_groups_schedule;
        parent::__init($db);
    }

    /**
     * Привязывает файлы из модуля Files
     */
    protected function afterInsert(){
        cot_files_linkFiles('sgrp_schedule', $this->_data['id']);
    }

    /**
     * @return bool
     */
    public function delete(){

        // Remove all files and images
        $files = files_model_File::find(array(
            array('file_source', 'sgrp_schedule'),
            array('file_item', $this->_data['id'])
        ));
        if(!empty($files)){
            foreach($files as $fileRow){
                $fileRow->delete();
            }
        }

         return parent::delete();
    }

    public static function fieldList() {
        return array(
            'id'  =>
                array(
                    'type'    => 'bigint',
                    'primary' => true,
                    'description' => 'id'
                ),
            'title'  =>
                array(
                    'type'      => 'varchar',
                    'length'    => '255',
                    'description' => 'Заголовок'
                ),
            'description'  =>
                array(
                    'type'      => 'varchar',
                    'nullable'  => true,
                    'default'   => '',
                    'length'    => '255',
                    'description' => 'Краткое описание'
                ),
            'text' =>
                array(
                    'type'      => 'text',
                    'nullable'  => true,
                    'default'   => '',
                    'description' => 'Текст'
                ),
            'begin'  =>
                array(
                    'type'      => 'datetime',
                    'default'   => date('Y-m-d H:i:s', cot::$sys['now']),
                    'description' => 'Дата начала'
                ),
            'end'  =>
                array(
                    'type'      => 'datetime',
                    'description' => 'Дата окончания'
                ),
            'created'  =>
                array(
                    'type'      => 'datetime',
                    'safe'      => true,
                    'description' => 'Дата создания'
                ),
            'created_by'  =>
                array(
                    'type'      => 'bigint',
                    'safe'      => true,
                    'description' => 'Кем создано'
                ),
            'updated'  =>
                array(
                    'type'      => 'datetime',
                    'safe'      => true,
                    'description' => 'Дата обновления'
                ),
            'updated_by'  =>
                array(
                    'type'      => 'bigint',
                    'safe'      => true,
                    'description' => 'Кем обновлено'
                ),
            'sgroup' =>
                array(
                    'type' => 'link',
                    'description' => 'Группа Вуза',
                    'link' =>
                        array(
                            'model'    => 'vuz_model_Group',
                            'relation' => Som::TO_ONE_NULL,
                            'label' => 'sgrp_title',
                        ),
                ),
        );
    }

    // === Методы для работы с шаблонами ===
    /**
     * Returns all Group tags for coTemplate
     *
     * @param vuz_model_Schedule|int $item vuz_model_Vuz object or ID
     * @param string $tagPrefix Prefix for tags
     * @param array $urlParams
     * @param int $textlength
     * @param bool $cacheitem Cache tags
     * @return array|void
     */
    public static function generateTags($item, $tagPrefix = '', $urlParams = array(), $textlength = 500, $cacheitem = true){

        static $extp_first = null, $extp_main = null;
        static $cacheArr = array();

        if (is_null($extp_first)){
            $extp_first = cot_getextplugins('vuz.schedule.tags.first');
            $extp_main  = cot_getextplugins('vuz.schedule.tags.main');
        }

        /* === Hook === */
        foreach ($extp_first as $pl){
            include $pl;
        }
        /* ===== */

        if(empty($urlParams)) $urlParams = array();
        if(empty($urlParams['m'])) $urlParams['m'] = 'group';
        if(empty($urlParams['a'])) $urlParams['a'] = 'schedule';

        if ( ($item instanceof vuz_model_Schedule) && is_array($cacheArr[$item->id]) ) {
            $temp_array = $cacheArr[$item->id];
        }elseif (is_int($item) && is_array($cacheArr[$item])){
            $temp_array = $cacheArr[$item];
        }else{
            if (is_int($item) && $item > 0){
                $item = vuz_model_Schedule::getById($item);
            }
            /** @var vuz_model_Schedule $item  */
            if ($item){

                // Права
                // Задание может править автор или староста
                $scheduleAuth['isadmin'] = cot_auth('vuz', 'a', 'A');
                if($scheduleAuth['isadmin']){
                    $scheduleAuth['auth_write'] = true;

                }elseif(cot::$usr['id'] == $item->created_by){
                    $scheduleAuth['auth_write'] = true;

                }else{
                    $grpAuth['isLeader'] = $item->sgroup->isLeader(cot::$usr);
                    if($grpAuth['isLeader']) $taskAuth['auth_write'] = true;

                }

                if(empty($urlParams['gid']) && !empty($grpIds)) $urlParams['gid'] = $item->sgroup->sgrp_id;
                $urlParams['sid'] = $item->id;

                $itemUrl = cot_url('vuz', $urlParams);
                $itemEditUrl = '';
                if($scheduleAuth['auth_write']){
                    $editUrlParams = $urlParams;
                    $editUrlParams['a'] = 'editSchedule';
                    $itemEditUrl = cot_url('vuz', $editUrlParams);
                }

                $itemDelUrl = '';
                if($scheduleAuth['auth_write']){
                    $editUrlParams = $urlParams;
                    $editUrlParams['a'] = 'deleteSchedule';
                    $itemDelUrl  = cot_confirm_url(cot_url('vuz', $editUrlParams),  'vuz', 'shedule_deleteConfirm');
                }

                $text = cot_parse($item->text);
                $text_cut = cot_cut_more($text);
                if ($textlength > 0 && mb_strlen($text_cut) > $textlength){
                    $text_cut = cot_string_truncate($text_cut, $textlength);
                }
                $cutted = (mb_strlen($text) > mb_strlen($text_cut)) ? true : false;

                $date_format = 'datetime_medium';
                $date_format = 'date_fulltext';
                $beginStamp = strtotime($item->begin);
                $endStamp = !empty($item->end) ? strtotime($item->end) : 0;
                $temp_array = array(
                    'URL' => $itemUrl,
                    'EDIT_URL' => $itemEditUrl,
                    'DELETE_URL' => $itemDelUrl,
                    'ID' => (int)$item->id,
                    'TITLE' => htmlspecialchars($item->TITLE),
                    'DISTPLAY_TITLE' => htmlspecialchars($item->displayTitle),
                    'DESC' => htmlspecialchars($item->description),
                    'BEGIN' => cot_date($date_format, $beginStamp),
                    'BEGIN_RAW' => $beginStamp,
                    'END' => cot_date($endStamp, $beginStamp),
                    'END_RAW' => $endStamp,
                    'TEXT' => $item->text,
                    'TEXT_CUT' => $text_cut,
                    'TEXT_IS_CUT' => $cutted,

                    'CREATED' => $item->created,
                    'CREATE_DATE' => cot_date($date_format, strtotime($item->created)),
                    'CREATED_RAW' => strtotime($item->created),

                    'UPDATED' => $item->updated,
                    'UPDATE_DATE' => cot_date($date_format, strtotime($item->updated)),
                    'UPDATED_RAW' => strtotime($item->updated),
                );

                /* === Hook === */
                foreach ($extp_main as $pl)
                {
                    include $pl;
                }
                /* ===== */
                $cacheitem && $cacheArr[$item->id] = $temp_array;
            }else{

            }
        }

        $return_array = array();
        foreach ($temp_array as $key => $val){
            $return_array[$tagPrefix . $key] = $val;
        }

        return $return_array;
    }

}

vuz_model_Schedule::__init();

Здесь очень важным является метод fieldList(), возвращающий массив с описанием полей в таблице. Обратите внимание на то, что модель не проверяет физическое наличие полей в таблице БД, а наивно доверяет возвращаемому массиву.
 Ключом массива является имя поля, а значением массив с описанием в формате ключ=>значение и может содержать следующие данные:

'name' - название поля
'primary' - может быть только у одного поля. Значение true указывает на то, что поле явлается первичным ключом таблицы.
'type' - тип поля. Это SQL тип или 'link', если это поле является связью с другой моделью.
'length' - необязательно. Длина значения, например для varchar
'nullable' - необязательно. 'nullable' => false указывает на то, что поле не может принимать пустое значение.
'default' - необязательно. Значение по умолчанию. При создании нового экземпляра модели поле будет проинициализировано этим значением. Однако при получении существующего объекта, поле будет проинициализировано данными из БД.
'description' - необязательно. Описание поля.
'safe' - необязательно. Если TRUE , то поле является «защищенным» при заполнении модели данными методом setData(), при попытке заполнения этого поля выбросит исключение, если пользователь не является администратором или действие просходит не в панели управления.

Обращаться к полям модели можно как к обычным свойствам объекта.

Например:

$sсhedule = vuz_model_Schedule::getById(15);   // Получить существующий объект
$endStamp = !empty($sсhedule->end) ? strtotime($sсhedule->end) : 0;

 

Связи между моделями

Модель может содержать связи с другими моделями. Поддерживаются связи один-ко-многим и многие-ко-многим. Например, наше расписание принадлежит конкретной группе ВУЗ'а реализованной моделью vuz_model_Group. Эта связь описывается так:

'sgroup' =>
    array(
        'name' => 'sgroup',
        'type' => 'link',
        'description' => 'Группа Вуза',
        'link' =>
            array(
                'model'    => 'vuz_model_Group',
                'relation' => Som::TO_ONE_NULL,
                'label' => 'title',
            ),
        ),

Здесь в массив с описанием доля добавляется элемент 'link', описывающий связь:

'model' - имя класса связываемой модели
'relation' - тип связи. Возможные значения (константы класса Som):
    - Som::TO_ONE  - один ко многим
    - Som::TO_ONE_NULL  - один ко многим, разрешено пустое значение
    - Som::TO_MANY - многие ко многим
    - Som::TO_MANY_NULL - многие ко многим, разрешено пустое значение
'label' - необязательно. Свойство связываемого класса которое можно использовать для автоматического вывода связанных объектов. Напрмер 'title'.
'localkey' - необязательно. Имя поля в данной модели (а точнее в таблице БД), где хранится id связанного объекта. Используется только для связей один-ко-многим т.к. для хранения связей многие-ко-многим необходима отдельная таблица в БД, которая при необходимости создается автоматически.
Если параметр localkey не указан, то будет использовано само поле в котором описана связь. В данном случае - sgroup. Обратите внимание, что поле должно существовать в таблице в БД.

При обращении к полю связанному с другой моделью получим ссылку на объект этой модели. Например:

$prod = Product::getById(2);
echo $prod->topic->name; // Выведет поле name экземпляра класса «ProductTopic» (для один-ко-многим)

или

$prod = Product::getById(2);
// Это сработает, если у нас для поля $topics объявлена связь многие-ко-многим
foreach ($prod->topics as $topic){
    // do something ...
    echo $topic->name;
}

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

Полю со связью один-ко-многим можно присвоить id связанного объекта или сам объект

Например:

$prod = Product::getById(5);
$topic = ProductTopic::getById(2);

$prod->topic = 2;      // Присвоили id
$prod->topic = $topic; // Присвоили экземпляр класса ProductTopic(). По сути эти действия идентичны.

Присваивать можно либо самому объявленному полю, либо полю из БД, указанному в localkey

Присвоить можно только экземпляр того класса, каким объявлена связь.

Присваивание значений полям со связями многие-ко-многим аналогично с той разницей, что помимо id или самого объекта допускается присваивание содержащего их массива.

 

Основные методы класса Som_Model_Abstract

static _init($db = 'db')

Статический конструктор. Должен вызываться при включении файла конкретного класса модели. Выполняет начальную инициализацию модели, заполняет свойства $_db и $_columns. Он принимает один единственный необязательный параметр $db - тип базы данных, по-умолчанию используется соединение с БД Cotonti.

 

__construct($data = null)

Конструктор экземпляра. Автоматически вызывается при создании экземпляра модели.

Может принимать в качестве параметра другой экземпляр той же модели или массив (ключ-значение). В этом случае поля объекта будут инициализированы соответствующими значениями.

 

protected function afterDelete()

Выполняется после удаления объекта. По умолчанию метод ничего не делает, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели.

 

protected function afterInsert()

Выполняется после добавления нового объекта в БД. По умолчанию метод ничего не делает, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели.

 

protected function afterSave()

Выполняется после сохранения объекта независимо от того, есть соотвествующая запись в БД или нет. По умолчанию метод ничего не делает, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели.

 

protected function afterSetData($data)

Выполняется после заполнения модели данными методом setData(); По умолчанию метод ничего не делает, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели.

 

protected function afterUpdate()

Выполняется после существующего объекта. По умолчанию метод ничего не делает, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели.

 

protected function beforeDelete()

Выполняется перед удалением объекта. По умолчанию метод возвращает TRUE, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели. Если метод вернет FALSE, удаление не произойдет и метод afterDelete() выполнен не будет.

 

protected function beforeInsert()

Выполняется перед сохранением нового объекта. По умолчанию метод возвращает TRUE, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели. Если метод вернет FALSE, добавления объекта в БД не произойдет и метод afterInsert() выполнен не будет.

 

protected function beforeSave($data)

Выполняется перед сохранением объекта независимо от того, есть соотвествующая запись в БД или нет. По умолчанию метод возвращает TRUE, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели. Если метод вернет FALSE, сохранение не произойдет и метод afterSave() выполнен не будет.

 

protected function beforeSetData($data)

Выполняется перед заполнением модели данными методом setData(); По умолчанию метод возвращает TRUE, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели. Если метод вернет FALSE, заполнение данными не произойдет и метод afterSetData() выполнен не будет.

 

protected function beforeUpdate()

Выполняется перед сохранением существующего объекта. По умолчанию метод возвращает TRUE, но Вы можете переопределить его для выполнения неких действий, спецефичных для Вашей модели. Если метод вернет FALSE, сохранение объекта не произойдет и метод afterUpdate() выполнен не будет.

 

static count($conditions)

Возвращает количество элементов, соотвествующих условию, переданному в параметре $conditions

 

dec($pair = array(), $conditions = '')

Декремент. Уменьшает заданные поля на заданные значения. Запись в БД производится сразу при вызове метода.

 

delete()

Удалить данных объект из базы данных

 

protected static fetch($conditions = array(), $limit = 0, $offset = 0, $order = '')

Защищенный Метод. Он осуществляет выборку объектов из БД. Возвращает массив экземпляров класса, если объект существует или null если ничего не найдено. Публичные методы getById(), fetchOne() и find() являются по сути обертками для этого метода и делегируют запрос ему.

Хоть этот метод и нельзя вызвать извне, но его полезно переопределять для создания выборок, специфичных для конкретной модели. В этом случае методы getById(), fetchOne() и find() будут делегировать запрос переопределенному методу, даже если сами они и не переопределены.

 

static fetchOne($conditions, $order = null)

Получить объект по заданным условиям. Возвращает экземпляр класса, если объект существует или null в противном случае.

где:

$conditions - условия
$order - условие для сортировки - поле или поля чере запятую. В последнем случае для каждого поля можено указать порядок сортировки (ASC или DESC). Также может принимать массив условий, элементами которого являются массивы, ключи которых - поля, а значения - порядок сортировки.

Получаемый объект кешируется на время выполнения аналогично методу getById().

 

static find($conditions, $limit = 0, $offset = 0, $order = '')

Найти объекты по заданным условиям. Возвращает массив экземпляров класса, если объект существует или null если ничего не найдено.

где:

$conditions - условия
$limit - Количество выбираемых элементов
$offset - Смещение выборки от начально элемента
$order - условие для сортировки - поле или поля чере запятую. В последнем случае для каждого поля можено указать порядок сортировки (ASC или DESC). Также может принимать массив условий, элементами которого являются массивы, ключи которых - поля, а значения - порядок сортировки.

 

static getById($pk, $staticCache = true)

Получить объект по первичному ключу. Возвращает экземпляр класса, если объект существует или null в противном случае. Если параметр $staticCache - true, то результат работы кешируется на время жизни скрипта. Т.е. если для конкретной модели вызывать несколько раз этот метод с одним и тем же параметром, запрос к БД выполняется только один раз, потом возвращается ссылка на объект из кеша. При сохранении/удалении объекта кеш сбрасывается.

Кеширование нужно отключить, если используется несколько объектов с одним первичным ключом и разными наборами опций.

 

static getDbConfig()

Возвращает настройки БД для данного объекта в виде массива.

 

static fields()

Возвращает массив полей, описанных в модели, с типами данных и связей.

 

getId()

Возвращает значение первичного ключа объекта

 

getValidators($field = null)

Возвращает валидаторы для указанного поля объекта или все валидаторы объекта. Валидаторы используются для проверки данных объекта при его сохранении.

 

inc($pair = array(), $conditions = '')

Инкремент. Увеличивает заданные поля на заданные значения. Запись в БД производится сразу при вызове метода.

 

static primaryKey()

Возвращает название поля первичного ключа модели.

 

rawValue($column)

Возвращает значение поля $column «как есть». Никакие преобразования не производятся. Для связей "ко многим" связанные объекты из БД не выбираются, возвращается массив значений первичного ключа связанных объектов (массив их id)

 

save($data = null)

Сохранить текущий объект. качестве аргумента можно передать массив (ключ-значение). В этом случае перед сохранением поля объекта будут перезаписаны данными из массива.

 

setData($data, $safe=true)

Безопасное заполнение модели данными. Принимает следующие параметры:

$data - массив данных в формате имя_поля => значение. Например $_POST.
$safe - Если параметр установлен в TRUE и при этом действие происходит не в панели управления и пользователь не администратор ($usr['isadmin'] != TRUE), то при попытке передать в массиве $data имя_поля, которое в описании в моделе имеет элемент 'safe' => TRUE, будет выброшено исключение.

Данные при установке значений проходят проверку на соотвествие типам данных. Вам не нужно заботиться о рутинной проверке вводимых пользователями данных.

 

setValidator($field, $validators)

Устанавливает валидатор(ы) для заданного поля объекта

 

toArray()

Возвращает поля текущего объекта в виде массива.

 

static updateRows($data, $condition = '')

Обновить все записи в таблице, соотвествующие условию $condition.

Принимает следующие параметры:
$data - массив данных в формате имя_поля => значение.
$condition - Любое допустимое условие для выборки

 

validate($fields = null)

Проверяет модель на наличие ошибок. Если в качестве параметра передан массив, то проверяет только те поля, которые перечислены в массиве. Проверка осуществляется при помощи установленных для данного объекта валидаторов. Также поля проверяются на соответствие типу данных.

Этот метод полезно переопределять для создания проверок спецефичных для конкретной модели

 

Получение объектов

Получение объектов осуществляется описанными выше методами getById(), fetchOne() и find()

 

Условия для выборки

Условия для выборки передаются через параметр $conditions методов fetchOne() и find().

Рассмотрим синтаксис этого параметра:

Он может быть:

Cтрока, соотвествующая SQL - синтаксису WHERE

Например:

$productArr = Product::find('id > 2 AND id_rasdel = 2');

В этом случае синтаксис зависит от типа БД и применять его стоит только в крайнем случае, т.к. может ограничить переносимость скрипта между разными типами БД. К тому же это не безопасно. Тут надо проверять передаваемые условия, чтобы исключить возможность sql инъекций, экранировать строковые значения.

 

Массив

Элемент массива строка

1. строка соотвествует формату <колонка> <оператор (<, >, =, больше или равно, меньше или равно, не равно)> <значение>

Например:

$products = Product::find(array('id >= 2', 'id < 5'));

Строковые значения в этом случае экранируются автоматически.

Будьте внимательны! Выборка

$this->item = Unittest_Model_Item::find(array('uti_id=1 OR uti_id=3'));

будет интерпретирована как

SELECT `unittest_item`.* FROM `unittest_item` WHERE (uti_id = '1 OR uti_id=3')

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

 

2. Строка не соответствует указанному формату

Например:

$products = Product::find(array('id IN(1,2,5)'));

В этом случае условие принимается 'как есть' и добавляется к предложению WHERE, по аналогии с Cтрока, соотвествующая SQL - синтаксису WHERE Элементы массива добавляются к предложению WHERE с добавлением AND между ними.

Нарпимер:

$products = Product::find(array('id >= 2', 'id < 5'));

Соотвествует условию:

WHERE katalogshop_sale.id >= 2 AND katalogshop_sale.id < 5

 

Элемент массива - массив

Массив может состоять из 4-х элементов, из которых первые два являются обязательными.

Нарпимер:

$products = Product::find(array(
    array('id', '2'),
    array('id', '5', '<','OR')
));

Расмотрим элементы массива:

1-ый - поле в БД
2-ой - значение
3-ий - операнд (< > = больше или равно, меньше или равно, не равно и т.п.), если не указано, то принимается равным '='
4-ый - Условие объединения (AND ИЛИ OR), если не указано, то принимается равным 'AND'

Так приведенный пример соотвествует условию:

WHERE katalogshop_sale.id = 2 OR katalogshop_sale.id < 5

Если перый элемент массива равен 'RAW' или 'SQL' то к предложению WHERE добавляется второй элемент (значение) «Как есть», по аналогии с Cтрока, соотвествующая SQL - синтаксису WHERE

Значение может быть массивом

Например:

$cats = array(1, 2, 4);
$prod = Product::find(array(
    array('id_rasdel', $cats)
));

Будет соответствовать:

WHERE katalogshop_sale.id_rasdel IN (1,2,4);

а

$cats = array(1, 2, 4);
$prod = Product::find(array(
    array('id_rasdel', $cats, '<>')
));

Будет соответствовать условию:

WHERE katalogshop_sale.id_rasdel NOT IN (1,2,4);

Строковые значения в переданном массиве экранируются.

Значение может быть NULL

Например:

$prod = Product::find(array(
    array('id_rasdel', null)
));

Будет соответствовать:

WHERE katalogshop_sale.id_rasdel IS NULL;

а

$prod = Product::find(array(
    array('id_rasdel', null, '<>')
));

Будет соответствовать условию:
WHERE katalogshop_sale.id_rasdel IS NOT NULL; 

 

Построение LIKE условий

Если значение содержит '*', то в предложение WHERE будет добавлено LIKE

Например:

$prod = Product::find(array(
    array('name', '*водонагреватель*')
));

Будет соответствовать условию:

WHERE katalogshop_sale.name LIKE '%водонагреватель%';

Так, к примеру для MySql '*' заменяется на '%'

Строковые значения экранируются.

 

 

Валидаторы. Проверка объектов.

Как уже отмечалось ранее, при сохранении объекта, его данные проходят проверку на соответствие типу данных, указанному в описании поля.

Дополнительную проверку данных можно обеспечить при помощи валидаторов.

Поддерживается 2 типа валидаторов:

 

Строковые валидаторы

В качестве строки выступает название типа данных: int, integer, bool, boolean, double, float, isnull, notnull, empty, notempty. Последние 4 - не являются типами данных и осуществляют проверку на соотвествие значения 'NULL' и на пустое значение.

 

Callback функции

В качестве валидатора можно передать функцию. Она должна по результатом проверки возвращать 'true' или строку с описанием ошибки.

Передача имени функции

Пример:

function myFunction($value){
// some validation
return true;
}
$prod = Product::getById(2);
$prod->setValidator('description', 'myFunction');

 

Использование замыканий

Пример:

$prod->setValidator('description', function($value){
    if(mb_strlen($value) > 30)  return true;
    return "Описание слишком короткое";
});

 

Использование методов классов

Пример:

class MyClass{
    public static function test($value)    {
        // some validation
        return true;
    }
}
$prod->setValidator('description', array('MyClass', 'test'));

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

class MyClass {
    public function myMethod($value){
        // some validation
        return true;
    }
}
$object = new MyClass;
$prod->setValidator('description', array($object, 'myMethod'));

И, наконец, Вы можете определить в своем классе магический метод _invoke(). В этом случае в качестве валидатора просто передайте экземпляр класса.

class MyClass{
    public function __invoke($value) {
        // some validation
        return true;
    }
}

$object = new MyClass();
$prod->setValidator('description', $object);

 

Установка валидаторов

Валидаторы можно установить на стадии проектирования модели или в период выполнения в контроллере.

Для установки валидатора в классе модели следует переопределить метод validators(). Например:

protected function validators() {
    return array(
        array('specialization,birthdate,city,category,staff,skills,education', 'required'),
        array('staff', function ($value) {
            // Сделать невозможным указание одновременно уровней в штатном расписании «Стажер» c любым другим уровнем
            if(!empty($value) && in_array(5, $value) && count($value) > 1) {
                return 'Нельзя указать «Стажер» одновременно с другими уровнями в штатном расписании';
            }
            $ret = (count($value) < 3) ? true : 'Можно использовать не более двух уровней в штатном расписании';

            return $ret;
        }),
    );
}

 

Во время выполнения установить валидатор для поля объекта можно методом setValidator($field, $validators) Он принимает в качестве параметров имя поля и валидатор любого из перечисленных типов.

Например:

$prod = Product::getById(2);
$prod->setValidator('description', 'notempty');
$prod->setValidator('description', function($value){
    if(mb_strlen($value) > 30)  return true;
    return "Описание слишком короткое";
});

 

Получение списка валидаторов

получить валидаторы можно методом getValidators($field = null) Он возвращает массив валидаторов, установленных для заданного поля или все валидаторы объекта, если параметр опущен.

 

Сеттеры и Геттеры

Как и указывалось выше, доступ к полям записи в БД, представленной объектом производится через его свойства. Однако Вы можете переопределить стандартное поведение для некоторых полей или даже добавить объекту новые свойства, не привязанные к полям в БД.

Делается это при помощи волшебных методов - сеттеров и геттеров.

Например вы в классе модели можете добавить новое динамическое поле:

setMyField($val){
    $this->_myField = $val;
}

getMyField(){
    return $val;
}

Как видим формат имени метода: set<имя_поля_с_большой_буквы>. Префикс «set» используется для сеттера, а «get» - для геттера.

После этого мы можем обращаться к этим полям:

$object = module_model_Object::getById(2);

$object->myField = 15;
echo $object->myField;

Данный пример очень простой. Вы можете создать более сложную логику для своих сеттеров и геттеров. Переопределение сеттеров и геттеров для существующих полей происходит аналогично. Просто создайте метод с названием set<имя_существующего_поля_с_большой_буквы>.

Обратите внимание на то, что сеттер должен принимать значение.

 
Автор: Alex
Опубликовано: Alex
Комментарии: (0)
Рейтинги:  
10

Теги:

Нет тегов

Комментарии:


Комментарии отсутствуют

Оставить комментарий:

* Просьба все технические вопросы, которые могут потребовать обсуждения, задавать на форуме.
** все некорректные и рекламные посты будут удаляться, ненормативная лексика и оскорбительные высказывания запрещаются.


Кликните для обновления

* Для редактирования комментария осталось 15 минут