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

Концепция ORM системы позволяет обращаться к записям и полям хранимых данных в базе данных (далее — БД), как к объектам и их свойствам. Соответственно ORM позволяет абстрагировать обращение к базе данных обращением к свойству объекта.

Назначение и архитектура

Модуль Data предоставляет абстракцию данных, позволяет работать с предзаданными структурами данных, как с объектами, а также управлять системными таблицами, типами данных и связями между ними.

Основные классы модуля:

  • Data — представляет точку входа для обращения к структурам данных
  • Entry — содержит представление единой записи конкретной структуры и хранит данные. Родительский класс который может наследоваться классами для специфических структур (скажем, только документов)
  • EntrySet — содержит представление множества записей конкретной структуры, а также хранит ее прототип

Интерфейс модуля

Data — точка входа для обращения к структурам данных в системе. Ссылка на модуль хранится в переменной $this->Data сценария, или возвращается статическим методом Kernel::Data() из любой другой точки.

Общий синтаксис обращения к объекту таков:

1
$this->Data-><strong>{ТИП СТРУКТУРЫ}</strong>-><strong>{НАЗВАНИЕ СТРУКТУРЫ}</strong>-><strong>{НАЗВАНИЕ ПОЛЯ/МЕТОДА}</strong>

На каждом из этих этапов возвращается объект, с которым можно оперировать определенным образом.

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

1
2
3
4
5
6
 foreach ($this->Data as $data)
  ... //Поочередно перечислит все типа: References, Documents, ...
foreach ($this->Data->References as $data)
  ... //Поочередно перечислит все справочники: Companies, Contacts, ...
foreach ($this->Data->References->Companies as $data)
  ... //Поочередно перечислит всеx контрагентов На третьем этапе мы уже имеем дело с EntrySet, который возвращает объекты Entry на каждой итерации.

Класс EntrySet

Объект EntrySet представляет собой набор записей одного типа. Можно рассматривать объект этого класса, как содержимое таблицы или как массив данных.
Этот класс представляет методы для фильтрации и оперирования с наборами данных.

Фильтрация

filter (string $string)
Фильтрует набор записей согласно правилу.

$string — Строка с правилом фильтрации.

Строка строится по принципу: {ПОЛЕ}{ОПЕРАЦИЯ}{ЗНАЧЕНИЕ}.

При последовательном написании «filter» накладывается условие «AND» (И).

Пример:

1
2
3
4
$_data = $this->Data->References->Companies; //Получаем список всех "Контрагентов"
$_data->filter("id!=5"); //Убираем из него компанию с id=5
$_data->filter("date>=22-05-2012"); //Оставляем только созданные после 22 мая
$_data->filter("status=1"); //И только со статусом 1

Или можно так:

1
$_data = $this->Data->References->Companies->filter("id!=5")->filter("date>=22-05-2012")->filter("status=1");

Каждый вызов filter изменяет данные в наборе. При этом, в переменной, разумеется, хранится только ссылка на набор данных, поэтому каждый следующий выбор уточняет набор.
В результате выполнения кода выше, в $_data будут перечислены все компании со «статусом»=»1», созданные после «22 мая», кроме компании с «id»!=»5″.

Если в фильтре перечислить несколько условий (массивом), то условие будет уже «OR» (логическое «ИЛИ»)

Пример:

1
$_data->filter(["author=" . $this->User->getEmployee(), "responsible contains name=" . $this->User->getEmployee()]);

На «Объект» будут наложен два условия:
1. поле «author» = пользователю системы
ИЛИ
2. поле «name» в табличная часть «responsible» содержит ссылку на пользователя системы

Пример использования like в фильтре:

1
$this->structure->filter("name like %".$filter_name."%");

Класс Database

Интерфейс модуля $this->DB.

QueryBuilder __get (string $tableName)
Инициализирует запрос к таблице. Возвращает объекта типа QueryBuilder.
$tableName — Имя таблицы.

Методы, определяющие тип запроса (Должны быть вызваны первыми в конструкторе, сразу после указания таблицы):

select ([string $field, …])
Создает запрос типа SELECT (выбор записей из таблицы).
$field — Название получаемого поля. Внимание: если ничего не указано, из таблицы берутся все имеющиеся поля. Никакие синонимы при этом не применяются (это следует особо учесть при использовании флага $dataNames, см. ниже).

update ()
Создает запрос типа UPDATE (изменение записей в таблице).

insert ()
Создает запрос типа INSERT (добавление записей в таблицу).

delete ()
Создает запрос типа DELETE (удаление записей из таблицы).
Методы, принимающие на вход тип Condition, всегда могут также принять строку с условием (например, «id=5»). Подробности смотрите в разделе с описанием класса Condition ниже.

join (string $table, [string $on])
INNER JOIN
$table — Имя таблицы
$on — Условие

leftJoin (string $table, [string $on])
LEFT JOIN
$table — Имя таблицы.
$on — Условие.

rightJoin (string $table, [string $on])
RIGHT JOIN
$table — Имя таблицы
$on — Условие

where (string $condition, …)
Добавить условие WHERE
$condition — Условие

having (string $condition, …)
Добавить условие HAVING
$condition — Условие

Обратите внимание: следующие функции принимают в качестве входных аргументов тип Column. Это значит, что им можно передавать не только строку с названием поля и сам объект типа Field, но также функцию и даже другой запрос. Соответствующие конструкторы будут вызваны автоматически. Подробности смотрите в разделе с описанием класса Column.

get (string $field, …)
Получить поле (для запросов SELECT). По умолчанию берутся все поля, однако если присутствует вызов этого метода, добавляются только указанные.
$field — Поле.

set (array $pair, …)
Установить значение поля (подходит для UPDATE и INSERT запросов)
$pair — Пара ключ-значение

group (string $field, …)
Группировать по полю
$field — Поле

order (string $field, …)
Упорядочить по полю
$field — Поле

limit (int $max, [int $startIndex])
Ограничивает количество строк с которыми оперирует запрос.
$max — Максимальное количество результатов (первые $)
$startIndex — Начальный индекс (начиная с $)

Result и DataResult execute (bool $dataNames)
Выполняет созданный запрос, возвращая результатом объект типа Result или DataResult (см. ниже).
$dataNames — Использовать ли название структур данных вместо названия таблиц. По умолчанию выключено.

getQuery ()
Получает копию созданного запроса, не выполняя его. Это полезно для создания подзапросов.

1
2
3
foreach ($this->DB->TABLE->select()->where("field>5")->join("TABLE2")->order("field")->limit(5)->execute() as $result) {
  ...
}

Вызов статического метода класса Database с названием создаваемого класа элемента запроса вызовет конструктор этого класса («сахар» для указания сложных пространств имен).

Класс Table

Представление таблицы.

__construct (string $name, [string $alias])
$name — Название таблицы.
$alias — Краткое имя таблицы в данном запросе.

Класс Pair

Представление пары ключ-значение (при передачи строк конструкторы вызываются автоматически).

__construct (string $field, string $value)
$field — Поле.
$value — Значение.

Класс Condition

Представление условия.

__construct ($left, const (IS_EQUAL,IS_LESS,IS_MORE,IS_NULL,IS_AND,IS_OR,IS_LIKE,IS_IN) $operation, $right, bool $invert)
$left — Левый операнд.
$operation — Код операции.
$right — Правый операнд.
$invert — Инверсия значения (NOT).

Существует также краткий синтаксис запросов. Для этого, вызовите статический метод с названием операции и передайте ему соответствующие аргументы (Database::_equal, Database::_like и т. д.). К тому же, любому методу, принимающему на вход объект типа Condition (за исключением конструктора этого объекта) Вы можете передать строку с выражением в формате {OPERAND}{OPERATION}{OPERAND} (number>5, id=3 и т. д.).

Класс Column

Представление колонки (поля).

__construct (string $content, [string $alias], [bool $stringAsValue])

$content — Содержимое колонки.
$alias — Название колонки в выводе.
$stringAsValue — Обращаться со строкой как со значением, а не с названием поля. По умолчанию, false.

Класс DBFunction

Представление функции

__construct (string $name, $argument, …)
$name — Название функции
$argument — Аргумент функции

Класс Field

Представление поля.

__construct (string $name, string $table)
$name — Название
$table — Таблица

Класс Result

Результат запроса (INSERT, UPDATE, DELETE).

bool isSuccessful ()
Успешно ли был выполнен запрос.

int getId ()
Вернуть добавленный ID (для запроса INSERT).

string result ()
Вернуть результат или сообщение об ошибке.

Пример:

1
$this->DB->TABLE->select(DB::DBFunction("SUM", "field"))->where(DB::_and(DB::_equal("field", 5), DB::_equal("field", 7))->getQuery();

Класс DataResult

Результат запроса с данными (SELECT).

Этот класс является итерируемым. Это значит что вы можете использовать его как массив: обращаться к его элементам по индексу, передавать его оператору foreach и т.д.

array result (int $num)
Вернуть строку с данными.
$num — Порядковый номер строки

Класс Data

Подробнее о методах интерфейса модуля Data см. соответствующий раздел документации. Здесь описаны интерфейсы основных классов: EntrySet для представление множества записей и Entry для представления одной.

Класс EntrySet

Множество записей.

__set (string $name, string $value)
Устанавливает значение поля для всех записей в наборе.
$name — Название поля
$value — Значение

sync ()
Синхронизирует записи с базой данных. Вносит изменения и получает текущее состояние.

save ()
Записывает изменения с объектами в наборе, однако в отличии от метода save не забираем данные из базы.

Entry create()
Создает новую запись и возвращает ее.

__call ()
Аналогично __set.

order (string $field, …)
Упорядочивает записи.
$field — Название поля

filter (string $condition)
Фильтрует набор записей по критерию
$condition — Строка с условием (см. выше)

getByField (string $name, string $value)
Отфильтровать по полю (аналогично вызову фильтра с операцией =).
$name — Название
$value — Значение

getById (int $id)
Получить запись (объект) по id (аналогично фильтрации по полю).
$id — Id искомой записи

getByOwner (Entry $id)
Получить записи по владельцу.
$id — Владелец или его id

limit (int $lim, int $startFrom)
Установить максимальное количество записей.
$lim — Количество

$startFrom — Отсчитывать объекты, начиная С__.

int num (bool $countOnly)
Вернуть количество записей в наборе.

$countOnly
Только подсчитать. Другими словами, синхронизации с базой не происходит.

int sum ()
Вернуть сумму по полю в наборе (Например, сумму всех «Счетов» по контрагенту)

string getName ()
Получить название объекта (иерархическое, например «references.companies»).

string getRealName ()
Получить реальное имя Объекта (языковое, с учетом локали, например «Контрагенты»).

Класс Entry

Отдельная запись.

Field __get (string $name)
Получить поле.
$name — Название поля

Field getFirstByFlag (string $flag)
Получить первое поле, имеющее указанный флаг.
$flag — Флаг

Field getField (string $name)
Получить объект поля
$name — Название поля

Для поля можно вызывать различные команды. В частности, метод addFilter для «поля-указателя» (Pointer) добавляет фильтрующее правило для структур на которые может ссылаться поле. Это не меняет само значение поля, однако полезно при выводе возможных вариантов заполнения поля.

__set (string $name, string $value)
Установить значение поля.
$name — Название поля
$value — Значение

markAsSaved ()
Пометить объект или поле, как уже сохраненные. В этом случае, при синхронизации с базой, поле не будет обновлено. Новый объект не будет добавлен. При синхронизации, значения полей существующих объектов будут перезаписаны. Используется при создании нового Объекта, например когда нужно подставить какое-то определенно значение в поле (например: статус — «Новый» в Заявке).

delete()
Установить пометку на удаление.

restore()
Восстановить (снять пометку на удаление).

Следует обратить внимание, что класс Entry также содержит все методы EntrySet, которые имеют для него смысл, такие как getName или sync. Обращение же к объекту типа EntrySet с методом от Entry (таким как __set) проведет операцию для всех записей или для прототипа (как в случае getField).

Entry move (array $args)
Подвинуть регистр.

$args — Ассоциативный массив пар ключ-значение для данных. Основные параметры регистра (такие как дата) проставляются автоматически.

Entry getOnDate ([int $date])
Подсчитать регистр на дату. Возвращает виртуальный псевдо-элемент типа Entry.

$date — Дата. По умолчанию, возвращается регистр на текущий день.

int countSum (string $field, array $params)

Подсчитать сумму поля регистра (для регистров накопления).

$field — Название поля
$params — Дополнительные параметры (фильтры).

Пример:

1
$this->Data->Registers[1]->move(["product" => $this->Data->References->Products->getById(1), "num" => -5]);

Класс User

Интерфейс модуля пользователей

const (AUTH_SUCCESS, AUTH_ALREADY_AUTHORIZED, AUTH_INCORRECT_PARAMS, AUTH_INCORRECT_LOGIN, AUTH_INCORRECT_PASSWORD, AUTH_REQUIRE_CAPTCHA, AUTH_INCORRECT_CAPTCHA, AUTH_LOGIN_BLOCKED) authorize (string $login, string $password, [ $captcha])

Авторизовать пользователя в системе. В ответ приходит один из кодов
$login — Логин
$password — Пароль
$captcha — Каптча (требуется только после ряда неверных наборов пароля)

bool isAuthorized()
Авторизован ли пользователь.

logout()
Выход (уничтожить текущую сессию).

string getLogin()
Получить логин пользователя

Entry getEmployee()
Получить сотрудника, привязанного к пользователю.

bool canPlay(string $scenario, string $action)
Имеет ли пользователь доступ к указанному сценарию

$scenario — Сценарий
$action — Действие

bool hasAccess(string $object, const (ACCESS_VIEW, ACCESS_READ, ACCESS_EDIT, ACCESS_ADD, ACCESS_DELETE, ACCESS_WIPE) $action, [string $field])
Имеет ли пользователя доступ на указанное действие к указанной структуре данных

$object — Структура
$action — Действие
$field — Поле (По-умолчанию — все поля)

const(FIELD_NO_ACCESS, FIELD_READ_ONLY, FIELD_FULL_ACCESS) getFieldAccess(string $object, string $field)
Получить уровень доступа к полю.

$object — Структура
$field — Поле

Класс Format

Работа с форматированием значений. Список форматов может добавляться и редактироваться в разделе ядерной конфигурации.

mixed __callStatic(mixed $value)
Передача значения в статический метод с названием формата вернет отформатированное значение.

$value — Значение.

Например:

1
Format::Number($x)

вернет $x приведенный к числу.

Класс String

Работа со строкой.

string money(int $sum)
Преобразование числа в сумму для вывода («1000» -> «1’000.00»).

$sum — Сумма

string bytes(int $number)
Возвращает отформатированное и сокращенное количество байтов.

$number — Количество байтов

string numberToText(int $number)
Записывает целое число прописью («100» -> «Сто»)

$number — Число (не больше 999 миллиардов 999 миллионов 999 тысяч 999).

string numberRuCase(int $number, string $nomS, string $genS, string $genPl)
Возвращает слово в падеже, подходящем числу (например, String::numberRuCase(25, кокос, кокоса, кокосов) вернет последний аргумент).

$number — Число.
$nomS — Именительный падеж, ед. число (согласуется с числом 1).
$genS — Родительный падеж, ед. число (согласуется с числами 2-4).
$genPl — Родительный падеж, мн. число (согласуется с числами 5-9).

Класс SMS

Работа с SMS-сообщениями. Чтобы отправить SMS, необходимо сначала получить код сессии, а затем передать его в метод sendSMS. Данные класс работает с SMS-провайдером «Devinotelecom». Логин, пароль и другие параметры от личного кабинета «Devinotelecom» заносятся в разделе «Настройки» — «Глобальные настройки» — «Настройка SMS» (/settings/globals/sms/)

string getCode()
Возвращает код новой сессии.

sendSMS (string $code, string $to, string $sourceName, string $text)
Отправляет СМС.

$code — Код, полученный методом выше
$to — Номер адресата (форматы, которые точно понимает система: +79xxxxxxxxx, 89xxxxxxxxx)
$sourceName — Имя отправителя. Важно передать ровно то имя, которое указано в настройках СМС-системы и зарегистировано в ЛК «Devinotelecom», иначе при отправке сообщения — Вы получите ошибку «Incorrect source address» или «Unhandled exception»
$text — Текст SMS. Обязательный параметр. Сообщение можно отправлять на русском или английском языке

Пример:

1
2
use Kernel\Framework\Sms;
Sms::sendSMS(Sms::getCode(), "89123456789", "RBS-CRM", "Привет, Нео!");

Отправка внутренних сообщений в CRM системе

Чтобы отправить сообщение необходиомо вызвать метод sendSMS.

1
$this->sendNotification(АДРЕСАТ (references.employees), ТИП (array || string: message; email; sms), ТЕКСТ, *ЗАГОЛОВОК, *ОТПРАВИТЕЛЬ (references.employees));

Пример:

1
2
use Kernel\Actions\Notifications; // подключаем класс
$this->sendNotification(1, array("message"), "Привет", Приветствие, 2); // отправляем

Вывод данных

Для вывода данных на шаблон используются блоки (см. выше) и функции:

  • printDataTable
  • fillFromData


printDataTable ($name, $params, $order = null, $struct = null, $mapFunction = null)

Функция используется обычно в «Формах списков» Объектов, где «Объект» определен заранее.

$name – название таблицы из шаблона в которую происходит вывод данных
$params – массив значений которые необходимо записать в таблицу, можно применять анонимные функции передавая параметр $obj. Например: «total» => function($obj) { return String::money($obj->total);
$order – по какому полю идет сортировка
$struct – структура для отображения, по умолчанию $this->structure
$mapFunction – анонимная функция принимающая на вход 2 параметра $obj и $row,
$obj – текущий объект, $row – строка, $row->params — дает вам доступ к управлению атрибутами строки таблицы.

Пример вывода данных в таблицу:

1
2
3
4
5
6
7
8
9
10
11
$this->printDataTable("form",
				      [
                       "number" => ["id", "name" => "number", "owner" => "owner.id"], 
                       "company" => ["id" => "owner.id", "name" => "owner.name"], 
                       "date", 
		       "comment",
                       "details"=>["id"=>"company_details.id", "name"=>"company_details.name", "owner" => "owner.id"],
                       "storehouse" => "storehouse.name",
                       "total" => function($obj) { return String::money($obj->total); },
                       "responsible" => "responsible.name",
"edit" => ["id", "company" => "owner"]], ["date", DESC]);

fillFromData($object, array $fields)
Функция используется для динамического вывода данных обычно на «Форме редактирования» Объекта

$object — список «Объектов»
$fields — массив полей

Пример: Вывод комментария последнего в Контрагенте

1
2
3
4
5
$this->tables->form->fillFromData($this->Data->References->comments->filter("owner=".$this->structure->id)->filter("visible=1")->order(['date', DESC])->limit(1), 
			[
			"date"=>function($obj){return $obj->date; }, 
			"text"=>function($obj){return preg_replace("/\n/", "<br/>", $obj->text); }, 
			"author" => "author.name"]);

Пример: Вывод товаров в форме редактирования «Счета»

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$this->tables->products->fillFromData($this->structure->products->filter("visible=1"),
				["num" => "id",
				"position"=>function($obj){ return "<input type='checkbox' class='prod' name='pos_".$obj->id."' id='".$obj->id."' value='1'/>";},
				"product" => function($obj){
					return "<a href='/products/".$obj->product->id."' target='_blank'>" .$obj->name."</a>";
				},
				"price_nds" => function($obj) { return String::money($obj->price_nds); },
				"nds" => function($obj) { return String::money($obj->nds); },
				"nds_procent"=>"nds_procent.name",
				"article" => "product.article",
				"number" => function ($obj) { return "<a href='javascript:open_table(".$obj->id.")'>".$obj->number."</a>" . ($obj->dispatched ? " <span class='dispatched_tip'>(" . ($obj->dispatched) . ")</span>" : ""); },
				"reserve",
				"total" => function($obj) { return String::money($obj->total); },
				"profit"=>function($obj) { return String::money($obj->profit); },
				"edit" => ["id", "order" => "owner", "company" => "owner.owner"],
				"delete" => ["id"]]);

Для отображения результата функции fillFromData используется следующая конструкция в Шаблоне:

1
2
3
4
5
6
7
8
9
10
11
12
[[dTable | name: products | id: prodTable | key: num]]
					[[column | table: products | name: position | width: 1%  | align: center]]
					[[column | table: products | name: num | width: 1% | header: № | type: num | align: center]]
					[[column | table: products | name: article | width: 10% | header: $data.products.article.name | align: center]]
					[[column | table: products | name: product | width: 50% | header: $data.products.product.name | align: left]]
					[[column | table: products | name: number | width: 10% | header: $data.products.number.name | align: center]]
					[[column | table: products | name: price_nds | width: 20% | header: $data.products.price_nds.name | align: right | tags:  nowrap]]
					[[column | table: products | name: nds | width: 10% | header: $data.products.nds.name | align: right]]
					[[column | table: products | name: total | width: 20% | header: $data.products.total.name | align: right | tags:  nowrap]]
					[[column | table: products | name: profit | width: 20% | header: $data.products.profit.name | align: right | tags:  nowrap]]  
					[[column | table: products | name: edit | type: edit | path: /companies/$company/orders/$order/products]]
					[[column | table: products | name: delete | type: delete]]

Добавление объекта

Для добавления структуры используется следующая конструкция:

Пример:

1
$this->Data->{Структура}->create();

Создаст и вернет новый объект для вашей структуры.

Примеры:

1
$this->Data->Documets->Orders->Сreate(); // создаст новый документ "Счет"

или можно так:

1
$this->Data->"Document.Orders"->Сreate(); // создаст новый документ "Счет"

Сохранение объекта

Для сохранения Объекта в базе данных используется метод sync()

Пример:

1
$this->structure->sync();

Пометка на удаление

Для того чтобы пометить объект на удаление используется метод delete()

Пример:

1
$this->structure->delete();

Не работает с наборами объектов, используйте foreach для обхода всех объектов.

Полное удаление оъекта (стирание)

Внимание! Данная операция может нарушит целостность вашей базы.

Для того чтобы полностью удалить объект из базы, используется метод wipe()

Пример:

1
$this->structure->wipe();

Не работает с наборами объектов, используйте foreach для обхода всех объектов.

Последние правки: 09.08.2016 11:43:57