1. Go to this page and download the library: Download beta/bx.model library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
beta / bx.model example snippets
use Bx\Model\AbsOptimizedModel;
class CatalogProduct extends AbsOptimizedModel
{
protected function toArray(): array
{
return [
'id' => $this->getId(),
'name' => $this->getName(),
];
}
public function getId(): int
{
return (int)$this['ID'];
}
public function setId(int $id)
{
$this['ID'] = $id;
}
public function getName(): string
{
return (string)$this['NAME'];
}
public function setName(string $name)
{
$this['NAME'] = $name;
}
}
use Bx\Model\Collection;
$priceItem1 = new Price([
'value' => 1000,
'currency' => 'RUB',
'group' = 1,
]);
$priceItem2 = new Price([
'value' => 2000,
'currency' => 'RUB',
'group' = 1,
]);
$priceItem3 = new Price([
'value' => 4000,
'currency' => 'RUB',
'group' = 2,
]);
$collection = new Collection(
$priceItem1,
$priceItem2,
$priceItem3
);
$collection->findByKey('value', 2000); // $priceItem2
$collection->find(function(Price $price) { // $priceItem1
return $price->getValueByKey('value') === 1000 &&
$price->getValueByKey('currency') === 'RUB'
});
$collection->filterByKey('group', 1); // вернет новую коллекцию состоящую из $priceItem1 и $priceItem2
$collection->filter(function(Price $price) { // вернет новую коллекцию состоящую из $priceItem2 и $priceItem3
return $price->getValueByKey('value') > 1000 &&
$price->getValueByKey('currency') === 'RUB'
});
$collection->column('value'); // [1000, 2000, 4000]
$collection->unique('currency'); // ['RUB']
$collection->remove($priceItem2); // удаляем элемент $priceItem2 из коллекции
$collection->append(new Price([ // добавляем новый элемент в коллекцию
'value' => 7000,
'currency' => 'RUB',
'group' => 2,
]));
$collection->first(); // $priceItem1
$collection->count(); // 3
count($collection); // 3
json_encode($collection); // JSON представление коллекции
$collection->jsonSerialize(); // вернет ассоциативный массив
use Bx\Model\ModelCollection;
$productData1 =[
'ID' => 11,
'NAME' => 'Product name 11',
];
$productData2 = [
'ID' => 21,
'NAME' => 'Product name 21',
];
$product3 = new CatalogProduct([
'ID' => 31,
'NAME' => 'Product name 31',
]);
$productCollection = new ModelCollection([
$productData1,
$productData2,
$product3
], CatalogProduct::class);
$productCollection->addModel(new CatalogProduct([
'ID' => 41,
'NAME' => 'Product name 41',
]));
$productCollection->add([
'ID' => 51,
'NAME' => 'Product name 51',
]);
use Bx\Model\MappedCollection;
use Bx\Model\MappedCollectionCallback;
$mappedCollection = new MappedCollection($productCollection, 'ID');
$mappedCollection[41]->getName(); // Product name 41
$mappedCollectionCallback = new MappedCollectionCallback(
$productCollection,
function(CatalogProduct $product){
return 'product_'.$product->getId();
}
);
$mappedCollectionCallback['product_41']->getName(); // Product name 41
use Bx\Modle\BaseModelService;
use Bx\Modle\ModelCollection;
class CatalogProductService extends BaseModelService
{
protected function getFilterFields(): array
{
return [
// указываем разрешенные для фильтрации поля
];
}
protected function getSortFields(): array
{
return [
// указываем разрешенные для сортировки поля
];
}
public function getList(array $params, UserContextInterface $userContext = null): ModelCollection
{
$list = CatalogProductTable::getList($params)->fetchAll();
return new ModelCollection($list, CatalogProduct::class);
}
public function getCount(array $params, UserContextInterface $userContext = null): int
{
$params['select'] = ['ID'];
$params['count_total'] = true;
$params['limit'] = 1;
return $this->getList($params, $userContext)->first();
}
public function getById(int $id, UserContextInterface $userContext = null): ?AbsOptimizedModel;
{
$params = [
'filter' => [
'=ID' => $id,
],
'limit' => 1,
];
return $this->getList($params, $userContext)->first();
}
function save(AbsOptimizedModel $model, UserContextInterface $userContext = null): Result
{
$data = [
'NAME' => $model->getName(),
];
if ($model->getId() > 0) {
return CatalogProductTable::update($model->getId(), $data);
}
$result = CatalogProductTable::add($data);
if ($result->isSuccess()) {
$model['ID'] = $result->getId();
}
return $result;
}
function delete(int $id, UserContextInterface $userContext = null): Result
{
return CatalogProductTable::delete($id);
}
}
use Bitrix\Main\Application;
$catalogProductService = new CatalogProductService();
$request = Application::getInstance()->getContext()->getRequest();
$queryParams = $request->getQueryParams();
$query = $catalogProductService->query(); // возвращается объект QueryModel
$query->loadFiler($queryParams) // загружаем фильтр из http запроса
->loadSort($queryParams) // загружаем параметры сортировки
->loadPagination($queryParams); // загружаем параметры пагинации
$query->hasFilter(); // проверяет наличие параметров для фильтрации
$query->getFilter(); // возвращает параметры для фильтрации
$query->hasSort(); // проверяет наличие параметров для сортировки
$query->getSort(); // возвращает параметры для сортировки
$query->hasLimit(); // проверяет наличие параметров для ограничения выборки
$query->getLimit(); // возвращает параметры ограничения выборки
$query->getPage(); // номер страницы для пагинации
$query->getOffset(); // номер элемента с которого начинается выборка
$productCollection = $query->getList(); // возвращает коллекцию товаров в соответствии со сформированными параметрами выборки
use Bitrix\Main\Application;
$catalogProductService = new CatalogProductService();
$request = Application::getInstance()->getContext()->getRequest();
$queryParams = $request->getQueryParams();
$query = $catalogProductService->query(); // возвращается объект QueryModel
$query->loadFiler($queryParams) // загружаем фильтр из http запроса
->loadSort($queryParams) // загружаем параметры сортировки
->loadPagination($queryParams); // загружаем параметры пагинации
$pagination = $query->getPagination(); // возвращается объект Pagination
$pagination->getPage(); // номер текущей страницы
$pagination->getCountPages(); // общее количество страниц
$pagination-getTotalCountElements(); // общее количество элементов
$pagination->getCountElements(); // количество элементов на текущей странице
$pagination->getLimit(); // максимальное количество элементов на странице
json_encode($pagination); // JSON представление
$pagination->toArray(); // представление в виде ассоциативного массива
use Bx\Model\BaseLinkedModelService;
use Bx\Model\FetcherModel;
use Bx\Model\Query;
use Bx\Model\Interfaces\FileServiceInterface;
class ExtendedCatalogProductService extends BaseLinkedModelService
{
/**
* @var FileServiceInterface
*/
private $fileService;
public function __construct(FileServiceInterface $fileService)
{
$this->fileService = $fileService;
}
protected function getFilterFields(): array
{
return [
// указываем разрешенные для фильтрации поля
];
}
protected function getSortFields(): array
{
return [
// указываем разрешенные для сортировки поля
];
}
protected function getLinkedFields(): array
{
/**
* В данном методе описываются внешние связи через FetcherModelInterface
* в виде ассоциативного массива
*/
$imageQuery = new Query();
$imageQuery->setFetchList([]); // пустой массив указывает на то что связанные модели выбирать не нужно, по-умолчанию выбираются все связанные модели
$imageQuery->setSelect(['ID', 'SIZE', 'DESCRIPTION']);
$imageQuery->setFilter('=CONTENT_TYPE' => ['jpg', 'png', 'gif']);
$docsQuery = new Query();
$docsQuery->setFetchList([]);
$docsQuery->setFilter('=CONTENT_TYPE' => ['doc', 'docx', 'pdf']);
return [
'image' => FetcherModel::initAsSingleValue( // будет выбрана одна модель
$this->fileService,
'image', // ключ по которому будет доступна связанная модель
'IMAGE_ID', // внешний ключ текущей сущности
'ID', // первичный ключ связанной сущности
$imageQuery // указываем доп. параметры выборки
),
'docs' => FetcherModel::initAsMultipleValue( // будет выбрана коллекция моделей
$this->fileService,
'docs',
'ID',
'PRODUCT_ID',
$docsQuery
)->castTo(AggreageDocumentModel::cass), // выбранная коллекция будет преобразована в указанную агрегационную модель
];
}
protected function getInternalList(array $params, UserContextInterface $userContext = null): ModelCollection
{
$list = CatalogProductTable::getList($params)->fetchAll();
return new ModelCollection($list, CatalogProduct::class);
}
public function getCount(array $params, UserContextInterface $userContext = null): int
{
$params['select'] = ['ID'];
$params['count_total'] = true;
$params['limit'] = 1;
return $this->getList($params, $userContext)->first();
}
public function getById(int $id, UserContextInterface $userContext = null): ?AbsOptimizedModel;
{
$params = [
'filter' => [
'=ID' => $id,
],
'limit' => 1,
];
return $this->getList($params, $userContext)->first();
}
function save(AbsOptimizedModel $model, UserContextInterface $userContext = null): Result
{
$data = [
'NAME' => $model->getName(),
];
if ($model->getId() > 0) {
return CatalogProductTable::update($model->getId(), $data);
}
$result = CatalogProductTable::add($data);
if ($result->isSuccess()) {
$model['ID'] = $result->getId();
}
return $result;
}
function delete(int $id, UserContextInterface $userContext = null): Result
{
return CatalogProductTable::delete($id);
}
}
use Bx\Model\Services\FileService;
$fileService = new FileService();
$productService = new ExtendedCatalogProductService($fileService);
$collection1 = $productService->getList([]); // будут выбраны все связанные модели
$collection2 = $productService->getList(['fetch' => []]); // связанные модели не будут выбраны
$collection3 = $productService->getList(['fetch' => ['image']]); // из связанных моделей будет выбраны только модели с ключом image
$firstModel = $collection1->first();
$firstModel['image']; // Объект File
$firstModel['docs']; // Объект AggreageDocumentModel
use Bx\Model\UI\Admin\ModelGrid;
;
$productService = new ExtendedCatalogProductService($fileService);
$grid = new ModelGrid(
$productService, // указываем сервис для работы с данными
'product_list', // указываем символьный идентификатор списка сущности
'ID' // ключ свойства модели для идентификации
);
/**
* Указываем поля фильтрации
*/
$grid->addSearchFilterField('name', 'Название');
$grid->addNumericFilterField('id', 'ID');
$grid->addBooleanFilterField('active', 'Активность')
->setTrueOption('Активно', 'Y')
->setFalseOption('Не активно', 'N');
$grid->addStringFilterField('article', 'Артикул');
$grid->addDateFilterField('date_create', 'Дата создания');
$grid->addListFilterField('status', 'Статус', [
1 => 'Новый',
2 => 'Опубликован',
3 => 'Снят с публикации',
]);
/**
* Указываем колонки для вывода в таблице
*/
$grid->addColumn('id', 'ID');
$grid->addColumn('name', 'Название');
$grid->addColumn('article', 'Артикул');
$grid->addColumn('date_create', 'Дата создания');
$grid->addCalculateColumn(
'status',
function(ExtendedCatalogProduct $product) {
return $product->getStatusName();
},
'Статус'
);
/**
* Указываем действия над элементами
*/
$grid->setSingleAction('Удалить', 'delete')
->setCallback(function (int $id) use ($productService) {
$productService->delete($id);
});
$grid->setSingleAction('Перейти', 'redirect')
->setJs('location.href="/bitrix/admin/product_detail.php?id=#id#"');
/**
* Указываем действия над элементами с условием отображения:
* если callback возвращает false, то действие на элементе не отобразится
*/
$grid->setConditionalSingleAction('Удалить', 'delete')
->setShowConditionCallback(function (ExtendedCatalogProduct $model) {
return !$model->hasValueKey('skuList') || empty($model->getValueByKey('skuList'));
})
->setCallback(function (int $id) use ($productService) {
$productService->delete($id);
});
/**
* Указываем действия над группой элементов
*/
$grid->setGroupAction('Удалить', 'delete')
->useConfirm('Подтвердить')
->setCallback(function (array $ids) use ($productService) {
foreach ($ids as $id) {
$productService->delete((int)$id);
}
});
$grid->setGroupAction('Опубликовать', 'accept')
->useConfirm('Подтвердить')
->setCallback(function (array $ids) use ($productService) {
$productCollection = $productService->getList([
'filter' => [
'=ID' => $ids,
],
'fetch' => [],
]);
foreach ($productCollection as $currentProduct) {
$currentProduct->setStatus(2);
$productService->save($currentProduct);
}
});
/**
* Добавляем кнопку в шапку справа от фильтра (вторая и последующие добавятся как выпадающее меню)
*/
$grid->addAdminButtonLink('Добавить', '/bitrix/admin/product_detail.php?lang='.LANG, 'btn_new');
/**
* Указываем, показывать ли кнопку экспорта в Excel (формирование excel-файла средствами битрикса)
*/
$grid->setShowExcelBtn(true);
/**
* Добавляем ссылку на строку таблицы (переход по двойному клику мышкой)
* Если не задать второй аргумент title, по умолчанию будет "Перейти"
* Если шаблон не подходит, можно использовать setDefaultRowLinkByCallback(callable $fnCalcLink, ?string $linkTitle = null)
*/
$grid->setDefaultRowLinkTemplate('/bitrix/admin/product_detail.php?id=#ID#', 'Изменить');
/**
* Добавляем ссылку на строку таблицы (переход по двойному клику мышкой, альтернативный метод)
*/
$grid->setDefaultRowLinkByCallback(function (ExtendedCatalogProduct $product) {
return '/bitrix/admin/product_detail.php?id='.$product->getId();
}, 'Изменить');