IO v7. Api (model) и работа с ними
Описание
Api (model, модель) - файл логики, работающий (чаще всего) в связке с class'ом таблицы базы данных.
Модель формирует API приложения.

Содержимое файла
У данной версии фреймворка есть 2 варианта наследования:
IO\Api\CoreApi- базовый класс моделей без привязки к class.IO\Api\CrudApi- класс моделей на основеIO\Api\CoreApi, с привязкой к class и поддержкой CRUD операций
IO\Api\CoreApi
<?php
namespace App\Api;
use IO\Api\CoreApi;
class ExampleApi extends CoreApi
{
/**
* Разрешения на выполнение методов модели
*/
public static function rules()
{
$rules = parent::rules();
$rules['static']['actionAbc'] = 1;
$rules['static']['actionDef'] = 1;
return $rules;
}
/**
* Инициализация
*/
public function onInit()
{
global $ioSession;
if (!$ioSession->isAuth()) return EIO_DENY;
$cabinet_pkid = $ioSession->getCurrentCabinetPkid();
if ($cabinet_pkid == null) return EIO_DENY;
//if (!$ioSession->permission('cluster_opt.trade.add')) return EIO_DENY;
return EIO_OK;
}
/**
* Перед выполнением запроса
*/
public function onBefore()
{
// ...
}
/**
* После выполнения запроса
*/
public function onAfter()
{
if($this->result->error_code != EIO_OK)
{
return;
}
if(in_array($this->action, ['abc']))
{
// ...
}
}
/**
* Пример пользовательского метода
*/
public function doAbc($result, $params)
{
$a = $params['a'] ?? 456;
return $result->showSuccess([
'ret_params' => $params,
'a' => $a,
]);
}
/**
* Пример пользовательского метода (обратная совместимость с IOv6) (не рекомендуется)
*/
public function actionDef($params)
{
$a = $params['a'] ?? 456;
return [
'ret_params' => $params,
'a' => $a,
];
}
}
IO\Api\CrudApi
<?php
namespace App\Api;
use IO\Api\CrudApi;
use App\Classes\Example;
class ExampleApi extends CrudApi
{
/**
* Разрешения на выполнение методов модели
*/
public static function rules()
{
$rules = parent::rules();
$rules['static']['actionGetByID'] = 1;
$rules['static']['actionSearch'] = 1;
$rules['static']['actionCreate'] = 1;
$rules['static']['actionSave'] = 1;
$rules['static']['actionDelete'] = 1;
$rules['static']['actionAbc'] = 1;
$rules['static']['actionDef'] = 1;
return $rules;
}
/**
* Структура модели
*/
public static function struct()
{
$struct = parent::struct();
$struct['class'] = Example::class;
$struct['fields'] = [
'pkid' => [
'datatype'=> 'integer',
'label' => 'ID записи',
'readonly'=> true,
],
'typeString' => [
'datatype'=> 'string',
'label' => 'Строчная переменная',
],
'typeVirtual' => [
'virtual' => true,
],
];
$struct['primary'] = [
'pkid',
];
return $struct;
}
/**
* Инициализация
*/
public function onInit()
{
global $ioSession;
if (!$ioSession->isAuth()) return EIO_DENY;
$cabinet_pkid = $ioSession->getCurrentCabinetPkid();
if ($cabinet_pkid == null) return EIO_DENY;
//if (!$ioSession->permission('cluster_opt.trade.add')) return EIO_DENY;
return EIO_OK;
}
/**
* Перед выполнением запроса
*/
public function onBefore()
{
// ...
}
/**
* После выполнения запроса
*/
public function onAfter()
{
if($this->result->error_code != EIO_OK)
{
return;
}
if(in_array($this->action, ['search', 'getByID']))
{
if($this->action == 'search') $goods_items = $this->result->items;
elseif($this->action == 'getByID') $goods_items = [ $this->result->item ];
// Загрузка ед измерения
$goods_items = $this->loadUnits($goods_items);
// Загрузка типов товара
$goods_items = $this->loadTypes($goods_items);
// Загрузка параметров товара
$goods_items = $this->loadParams($goods_items);
// Загрузка фото товара
$goods_items = $this->loadPhotos($goods_items);
// Загрузка категории товара
$goods_items = $this->loadCategories($goods_items);
// Загрузка категории товара
$goods_items = $this->loadOffersCount($goods_items);
// To Array
$goods_items = dbToArray($goods_items);
if($this->action == 'search') $this->result->items = $goods_items;
elseif($this->action == 'getByID') $this->result->item = $goods_items[0];
}
elseif(in_array($this->action, ['save']))
{
if($this->item == null) return;
// Сохранение параметров товара
$this->saveParams();
// Сохранение категории товара
$this->saveCategories();
// Загрузка фото товара
$this->savePhotos();
}
}
/**
* Search filter
*/
public function onSearchFilter($search_filter)
{
global $ioSession;
$cabinet_pkid = $ioSession->getCurrentCabinetPkid();
$search_filter['cabinet_pkid'] = $cabinet_pkid;
$search_filter['is_deleted'] = 0;
$search_filter = parent::onSearchFilter($search_filter);
return $search_filter;
}
/**
* Search params
*/
public function onSearchParams($search_params)
{
$search_params['fields'] = ['*'];
$search_params['order'] = [
'pkid' => 'desc',
];
$search_text = isset($params['search_text']) ? $params['search_text'] : '';
if (strlen($search_text) > 0)
{
$search_params['filter']['~search'] = $search_text;
$search_params['fields'][] = "#MATCH (search) AGAINST (\"" .
\IO\IO_MYSQL_PDO::escape($search_text) . "\" IN BOOLEAN MODE) as full_text";
$search_params['order'] = [
'full_text' => 'desc',
'pkid' => 'desc',
];
}
$search_params = parent::onSearchParams($search_params);
return $search_params;
}
/**
* Update data event
*/
public function onUpdateData($save_data, $update_data)
{
return $update_data;
}
/**
* Update item event
*/
public function onUpdateItem($save_data, $update_data)
{
global $ioSession, $iodb;
$item = $this->item;
// Если товар создается
if ($this->action == 'create')
{
// Type ID
$type_id = $save_data['type_id'];
$item->type_id = $type_id;
// Cabinet pkid
$cabinet = $ioSession->getCurrentCabinet();
$cabinet_pkid = $cabinet['cabinet_pkid'] ?? 0;
$cabinet_number = $cabinet['cabinet_number'] ?? 0;
$item->cabinet_pkid = $cabinet_pkid;
$item->cabinet_number = $cabinet_number;
// Код товара
$q = "
SELECT code_good + 1 AS new_code_good
FROM trade_goods WHERE `cabinet_pkid`=:cabinet_pkid
order by code_good desc limit 1
";
$new_code_good = $iodb->get_var('new_code_good', $q, [
':cabinet_pkid' => $cabinet_pkid
]);
$item->code_good = $new_code_good;
}
// Строка поиска
$search_text = [
xarr($save_data, ['meta', 'name', 'en']),
xarr($save_data, ['meta', 'name', 'ru']),
xarr($save_data, ['meta', 'name', 'kz']),
];
//$search_text = array_filter($search_text, mb_trim);
$item->search = implode(' ', $search_text);
// Мета информация
$item->meta = [
'name' => [
'en' => xarr($save_data, ['meta', 'name', 'en']),
'ru' => xarr($save_data, ['meta', 'name', 'ru']),
'kz' => xarr($save_data, ['meta', 'name', 'kz']),
],
'description' => [
'en' => xarr($save_data, ['meta', 'description', 'en']),
'ru' => xarr($save_data, ['meta', 'description', 'ru']),
'kz' => xarr($save_data, ['meta', 'description', 'kz']),
],
];
// Ед измерения
$item->unit_type_pkid = $save_data['unit_type_pkid'] ?? null;
$item->unit_pkid_default = $save_data['unit_pkid_default'] ?? null;
// Главная фото
$new_photos = xarr($this->params, ['item', 'photos'], []);
if ($new_photos && count($new_photos) > 0)
{
$main_photo = $new_photos[0];
$item->main_photo_pkid = $main_photo['pkid'];
}
else
{
$item->main_photo_pkid = null;
}
}
/**
* Пример пользовательского метода
*/
public function doAbc($result, $params)
{
$a = $params['a'] ?? 456;
return $result->showSuccess([
'ret_params' => $params,
'a' => $a,
]);
}
/**
* Пример пользовательского метода (обратная совместимость с IOv6) (не рекомендуется)
*/
public function actionDef($params)
{
$a = $params['a'] ?? 456;
return [
'ret_params' => $params,
'a' => $a,
];
}
}
Пользовательские методы
Все пользовательские do и action методы пишутся по подобию данных методов, начиная с префикса do, либо action (по старому, но не рекомендуется) и далее через CamelCase.
Разрешение на выполнение метода в rules() указывается с префиксом action, независимо от того, с каким префиксом был объявлен сам метод (do или action).
/**
* Пример пользовательского метода
*/
public function doAbc($result, $params)
{
$a = $params['a'] ?? 456;
return $result->showSuccess([
'ret_params' => $params,
'a' => $a,
]);
}
/**
* Пример пользовательского метода (обратная совместимость с IOv6) (не рекомендуется)
*/
public function actionDef($params)
{
$a = $params['a'] ?? 456;
return [
'ret_params' => $params,
'a' => $a,
];
}
ВНИМАНИЕ
Пользовательские методы обязательно должны быть public и не static. Выход из метода обязательно должен сопровождаться оператором возврата return.
ApiResult методы
В пользовательских do методах есть обязательный аргумент $result. Это объект экземпляра класса IO\Api\ApiResult. Метод именно этого экземпляра класса должен быть возвращен через оператор возврата.
toArray()
toArray(): array
assign()
assign(
array $data
): object(IO\Api\ApiResult $this)
showResult()
showResult(
array $result = [],
string $error_str = '',
int $error_code = EIO_UNKNOWN
): object(IO\Api\ApiResult $this)
showSuccess()
showSuccess(
array $result = [],
string $error_str = ''
): object(IO\Api\ApiResult $this)
showException()
showException(
array $result = [],
object(Exception) $e,
int $error_code = EIO_UNKNOWN
): object(IO\Api\ApiResult $this)
errorByCode()
errorByCode(
int $error_code,
array $arr = []
): object(IO\Api\ApiResult $this)
errorNoPermissions()
errorNoPermissions(): object(IO\Api\ApiResult $this)
offsetExists()
offsetExists(
string $key
): bool
offsetUnset()
offsetUnset(
string $key
): void
offsetGet()
offsetGet(
string $key
): string|null
offsetSet()
offsetSet(
string $key,
mixed $value
): void
Вызов api метода
В route и api
$ret = \IO\Core::callAction(
'app.api.example.abc', // или по старому 'app.model.example.abc'
[
'a' => 123,
]
);
if($ret['error_code'] ?? EIO_FALSE == EIO_OK)
{
$ret_params = $ret['ret_params'] ?? [];
$recipientEmail = $ret['recipient_email'] ?? null;
$a = $ret['a'] ?? null;
v_dump($ret_params);
v_dump($recipientEmail);
v_dump($a);
}
else
{
echo 'error ' . ($ret['error_code'] ?? EIO_FALSE) . ': ' . ($ret['error_str'] ?? '');
}
v_dump($ret);
В Twig
{% set r = ioCallAction(
'app.api.example.abc', // или по старому 'app.model.example.abc'
{
'a' => 123,
}
) %}
{{v_dump(r)}}
Через URL
Нужно прописать в браузере путь до нашей модели по типуhttps://site.kz/entity/app.api.example.abc илиhttps://site.kz/entity/app.model.example.abc
где .abc это пользовательский метод
Чтобы получить результат в формате JSON, нужно добавить GET параметр &resultType=json в конце URL.

Доступные методы CoreApi
rules()
static rules(): array
onInit()
onInit(): int
onBefore()
onBefore()
onAfter()
onAfter()
Доступные методы CrudApi
Класс CrudApi наследуется от CoreApi.
struct()
Структура Api
static struct(): array
tablename()
Return table name
static tablename(): string
onSearchFilter()
Search filter
onSearchFilter(): array
onSearchParams()
Search params
onSearchParams(): array
onUpdateData()
Update data event
onUpdateData(
array $save_data,
array $update_data
): array
onUpdateItem()
Update item event
onUpdateItem(
array $save_data,
array $update_data
): array
getSearchFilter()
Returns search filter
getSearchFilter(
array $api_filter
): array
getItemByID()
Получить запись по ID
getItemByID(
int|string $pkid
): array|null
saveItem()
Сохранить данные item в базе данных
saveItem(
array $save_data
)
parseApiFilterKey()
Parse api filter key
static parseApiFilterKey(
string $key
): array
convertSearchFilterToDb()
Convert api filter to DB
static convertSearchFilterToDb(
array $filter
): array
actionGetByID()
Получить запись по ID
actionGetByID(
object(IO\Api\ApiResult) $result,
array $params
): array
actionSearch()
Поиск записей
actionSearch(
object(IO\Api\ApiResult) $result,
array $params
): array
actionCreate()
Добавление объекта
actionCreate(
object(IO\Api\ApiResult) $result,
array $params
): array
actionSave()
Редактирование объекта
actionSave(
object(IO\Api\ApiResult) $result,
array $params
): array
actionDelete()
Удаление объекта
actionDelete(
object(IO\Api\ApiResult) $result,
array $params
): array
Прочее
event метода нет, там onInit, onUpdate, onSearch...