BMC IO DocsBMC IO Docs
IO v6
IO v7
Notes
Docs
IO v6
IO v7
Notes
Docs
  • IO Framework v7

    • О фреймворке
    • Что изменилось в 7 версии
    • Структура
    • Доступ к участкам проекта
    • Разворачивание нового проекта
  • Backend

    • Настройки проекта Conf.php
    • Настройки модуля Module.php
    • Настройки composer
    • Функции фреймворка
    • Глобальные переменные
    • Константы фреймворка
    • Event класс
    • Core класс
    • Route и работа с ними
    • Request и работа с ними
    • Middleware и работа с ними
    • Class и работа с ними
    • Api model и работа с ними
    • Template и работа с ними
    • Мультиязычность и словарь фраз
    • Bin скрипты и работа с ними
    • Cron скрипты и работа с ними
    • $ioSession и работа с сессией
    • $ioHash и работа с кешем
    • $ioXCache и работа с кешем
    • $iodb и работа с базой данных
  • Frontend

    • Twig шаблонизатор и работа с ним
    • Twig функции
    • Twig фильтры
    • Twig контекст
    • Настройка NPM
    • Сборка Frontend составляющей
    • Обращение к Api через JS
    • Хранилище (store)
    • Навигация в хосте
    • Навигация в микрофронтенде
    • Параметры микрофронтенда
    • Проверка полномочий

IO v7. Api (model) и работа с ними

  • Описание
  • Содержимое файла
    • IO\Api\CoreApi
    • IO\Api\CrudApi
  • Пользовательские методы
  • ApiResult методы
    • toArray()
    • assign()
    • showResult()
    • showSuccess()
    • showException()
    • errorByCode()
    • errorNoPermissions()
    • offsetExists()
    • offsetUnset()
    • offsetGet()
    • offsetSet()
  • Вызов api метода
    • В route и api
    • В Twig
    • Через URL
  • Доступные методы CoreApi
    • rules()
    • onInit()
    • onBefore()
    • onAfter()
  • Доступные методы CrudApi
    • struct()
    • tablename()
    • onSearchFilter()
    • onSearchParams()
    • onUpdateData()
    • onUpdateItem()
    • getSearchFilter()
    • getItemByID()
    • saveItem()
    • parseApiFilterKey()
    • convertSearchFilterToDb()
    • actionGetByID()
    • actionSearch()
    • actionCreate()
    • actionSave()
    • actionDelete()
  • Прочее

Описание

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...

Prev
Class и работа с ними
Next
Template и работа с ними