beta/bx.model.ext

扩展模型

安装: 1

依赖: 0

建议者: 0

安全: 0

星标: 1

关注者: 2

分支: 0

开放问题: 0

类型:bitrix-module

1.0.1 2022-02-16 13:39 UTC

This package is auto-updated.

Last update: 2024-09-17 13:42:45 UTC


README

此模块包含一系列用于模型服务的装饰器

  • LazyModelService - 实现按需加载数据的机制。
  • StorageModelService - 实现Indenty map机制,包含存储已请求的对象的存储库。
  • TransactionModelService - 包含记录/删除操作的存储库,用于创建总事务。

LazyModelService

包含模型服务装饰器(LazyModelService)、模型装饰器(LazyModel)和用于按需大量加载数据的独立集合(LazyModelCollection)。

工作示例

use Bx\Model\Ext\DataHelper;
use Bx\Model\Ext\LazyModelService;
use Bx\Model\Ext\LazyModel;
use Bitrix\Main\Loader;

Loader::includeModule('bx.model.ext');
$someServiceModel = new SomeServiceModel();     // некий сервис для работы с моделями
$lazyServiceModel = new LazyModelService(
    $someServiceModel,
    SomeModel::class,       // класс модели данных
    'ID'                    // первичный ключ
);

$collection = $lazyServiceModel->getList([
    'select' => ['ID'],
]);                             // [['ID' => 1], ['ID' => 2], ['ID' => 3]]

$firstModel = $collection->first();
$firstModel->load();            // запрашиваем все данные по данной модели
DataHelper::load($firstModel);  // альтернативный способ запроса данных модели

print_r(iterator_to_array($firstModel));    // ['ID' => 1, 'NAME' => 'first'...]
print_r(iterator_to_array($collection));    // [['ID' => 1, 'NAME' => 'first'...], ['ID' => 2], ['ID' => 3]]

$collection->load();            // запрашиваем все данные по моделям коллекции
DataHelper::load($collection);  // альтернативный способ запроса данных коллекции

print_r(iterator_to_array($collection));    // [['ID' => 1, 'NAME' => 'first'...], ['ID' => 2, 'NAME' => 'second'...], ['ID' => 3, 'NAME' => 'third'...]]

var_dump($first instanceof SomeModel);  // false
var_dump($first instanceof LazyModel);  // true

// данный метод позволяет получить инкапсулированную модель
var_dump($first->getOriginalObject() instanceof SomeModel); // true
/** 
 * альтернативный метод для запроса инкапсулированной модели, 
 * в отличии от первого метода позволяет пройти по всей цепочки 
 * декоратов и извлечь исходную модель 
 * **/
var_dump(DataHelper::extractOriginalObject($first) instanceof SomeModel); // true

var_dump($lazyServiceModel->getOriginalObject() instanceof SomeServiceModel); // true
var_dump(DataHelper::extractOriginalObject($lazyServiceModel) instanceof SomeServiceModel); // true

StorageModelService

包含模型服务装饰器(LazyModelService),它会保存请求过的模型列表,并在重复请求相同模型时从内部存储中提取它们。这样,可以避免对象的重复,并减少对数据源的数据访问次数。默认的存储机制使用LRU缓存。

工作示例

use Bx\Model\Ext\StorageModelService;
use Bx\Model\Ext\Common\ModelStorage;
use Bx\Model\Ext\Common\LruRemoveStrategy;
use Bitrix\Main\Loader;

Loader::includeModule('bx.model.ext');

$someServiceModel = new SomeServiceModel();     // некий сервис для работы с моделями
$modelSotrage = new ModelStorage(               // создаем хранилище для моделей
    new LruRemoveStrategy(),                    // стратегия чистки кеша
    'ID',                                       // первичный ключ
    [],                                         // элементы для добавления в хранилище
    1000                                        // максимальное количество элементов в хранилище
);
$storageServiceModel = new StorageModelService(
    $someServiceModel,
    SomeModel::class,
    'ID',
    $modelSotrage
);

$model1 = $storageServiceModel->getById(1);
$model2 = $storageServiceModel->getById(1);
$model3 = $storageServiceModel->getList(['filter' => ['=ID' => 1]])->first();

var_dump($model1 === $model2);      // true, один и тот же объект
var_dump($model1 === $model3);      // true, один и тот же объект

TransactionModelService

包含模型服务装饰器(TransactionModelService)和模型装饰器(StateModel),允许跟踪模型中的数据变化。所有写入和删除操作都收集到单独的操作存储库中,稍后可以作为一个单一事务启动,或实现大量数据更新的场景,或实现工作单元模式。

工作示例

use Bx\Model\Ext\DataHelper;
use Bx\Model\Ext\TransactionModelService;
use Bx\Model\Ext\Common\OperationHolder;
use Bitrix\Main\Loader;

Loader::includeModule('bx.model.ext');
$someServiceModel = new SomeServiceModel();     // некий сервис для работы с моделями
$operationHolder = new OperationHolder();       // хранилище операций
$transactionServiceModel = new TransactionModelService(
    $operationHolder,
    $someServiceModel,
    SomeModel::class
);

$model = $transactionServiceModel->getById(1); // ['ID' => 1, 'NAME' => 'Original name']
$model->setName('Name 1');
$model['NAME'] = 'Name 2';

var_dump($model->isChanged());              //true

$state = $model->offsetGetState('NAME');    // хранище состояний указанного поля
print_r(iterator_to_array($state));         // ['Name 2', 'Name 1', 'Original name']

var_dump($model->getName());                // 'Name 2'
var_dump($model['NAME']);                   // 'Name 2'

$model->loadPrevState('NAME');              // загружаем предыдущее состояние поля

var_dump($model->getName());                // 'Name 1'
var_dump($model['NAME']);                   // 'Name 1'

$model->loadPrevState('NAME');              // загружаем предыдущее состояние поля

var_dump($model->getName());                // 'Original name'
var_dump($model['NAME']);                   // 'Original name'

$model->loadNexState('NAME');               // загружаем следующее состояние поля

var_dump($model->getName());                // 'Name 1'
var_dump($model['NAME']);                   // 'Name 1'

$model->loadOriginalState();                // загружаем исходное состояние всех полей модели

var_dump($model->getName());                // 'Original name'
var_dump($model['NAME']);                   // 'Original name'

$model->loadLastState();                    // загружаем последнее состояние всех полей модели

var_dump($model->getName());                // 'Name 2'
var_dump($model['NAME']);                   // 'Name 2'

// запрашиваем измененные данные
var_dump($model->getChangesData());         // ['NAME' => 'NAME 2']

$result = $transactionServiceModel->save($model);     // получаем экземпляр TransactionResult, данная операция добавлена в хранилище операций, но не была применена
$result->commit();              // мы можем применить данную операцию на месте
DataHelper::commit($result);    // или применить ее таким способом

// запрос всех опреаций для указанного сервиса
$operationHolder->getOperationList(SomeServiceModel::class);
// запрос опреаций создания для указанного сервиса
$operationHolder->getCreateOperationList(SomeServiceModel::class); 
// запрос опреаций обновления для указанного сервиса
$operationHolder->getUpdateOperationList(SomeServiceModel::class); 
// запрос опреаций создания для указанного сервиса
$operationHolder->getRemoveOperationList(SomeServiceModel::class);

$operationHolder->actualizeOperations();    // данный метод позволяет отчистить хранилище от ранее выполненных операции и устанить конфликтующие операции

$operationHolder->commit();             // выполнить все опреции из хранилища и отчистить хранилище
DataHelper::commit($operationHolder);   // альтернативный метод выполнения операций из хранилища