b24/devtools

dev-main 2024-07-07 10:27 UTC

This package is auto-updated.

Last update: 2024-09-07 10:54:56 UTC


README

安装

composer require b24/devtools

连接

使用这些工具需要连接 Composer 的自动加载器。示例连接

local/php_interface/init.php
require $_SERVER['DOCUMENT_ROOT'] . '/vendor/autoload.php';

智能流程

从头开始创建智能流程

$mapper = \B24\Devtools\Crm\Smart\Mapper::create(title: 'TEST', code: 'TEST', name: 'TEST'|null);

成功创建后将返回 \B24\Devtools\Crm\Smart\Mapper 类的对象

class Mapper
{
    public readonly \B24\Devtools\Crm\Smart\SmartDynamic $smart;
    public readonly string $entityName;

    public function __construct(
        public readonly int $id,
        public readonly int $entityTypeId,
        public readonly string $code,
    ) {}
}

删除智能流程

通过字符码,或通过实体的 ENTITY_ID

\B24\Devtools\Crm\Smart\Mapper::deleteByCodeOrEntityId($code|$entityTypeId)
// Либо
\B24\Devtools\Crm\Smart\Mapper::deleteByCodeOrEntityIdIfExists($code|$entityTypeId)

通过 b_crm_dynamic_type 表的 ID

\B24\Devtools\Crm\Smart\Mapper::deleteById($id);
// Либо
\B24\Devtools\Crm\Smart\Mapper::deleteByIdIfExists($id)

替换服务容器

使用示例

use Module\Helpers\Crm\Replacement\Container;

new Container([
    'TEST' => FactoryTest::class
]);

构造函数的参数是一个数组,其中 CODE 是智能流程的键,值是其工厂的命名空间。这允许在智能流程元素上调用前和后的事件。

示例工厂

use Bitrix\Crm\Item;
use Bitrix\Crm\Service;
use Bitrix\Crm\Service\Context;
use Bitrix\Crm\Service\Operation;

class FactoryTest extends Service\Factory\Dynamic
{
    public function getAddOperation(Item $item, Context $context = null): Operation\Add
    {
        $operation = parent::getAddOperation($item, $context);

        $operation->addAction(
            Operation::ACTION_BEFORE_SAVE,
            new AddHandler()
        );

        return $operation;
    }
}

处理添加元素的的事件处理器

use Bitrix\Crm\Service\Operation;
use Bitrix\Main\Result;
use B24\Devtools\Crm\ResultOperationTrait;

class AddHandler extends Operation\Action
{
    use ResultOperationTrait;

    public function process(\Bitrix\Crm\Item $item): Result
    {
        return $this
            ->error('Ошибка 1')
            ->error('Ошибка 2')
            ->result();
    }
}

image

处理智能流程实体

\B24\Devtools\Crm\Smart\SmartProcess 继承自 \B24\Devtools\Crm\Smart\SmartDynamic

$entityTypeId = \B24\Devtools\Crm\Smart\SmartProcess::getIdByCode('TEST');

$smart = new \B24\Devtools\Crm\Smart\SmartProcess($entityTypeId);
// Либо так: $smart = new \B24\Devtools\Crm\Smart\SmartProcess('TEST');

$smart->getFactory(); // Вернёт фабрику смарт-процесса
$smart->getFactoryId(); // ID смарт-процесса
$smart->getEntityName(); // Название объекта смарт-процесса, CRM_2 (например)
$smart->compileClass(); // Отдаст неймспейс класса ORM смарт-процесса
$smart->getContainer(); // Отсюда же можно вытащить сервис контейнер
$smart->getRelationManager(); // RelationManager

对 b_crm_entity_relation 表执行 CRUD 操作

// Чтение связей //

$children = \B24\Devtools\Crm\Relation\Manager::searchChildren(\CCrmOwnerType::Quote, 1)
    ->getAll(); // Массив из ItemIdentifier всех привязанных детей к Предложению

$children = \B24\Devtools\Crm\Relation\Manager::searchChildren(\CCrmOwnerType::Quote, 1)
    ->withEntityTypeId(152); // Массив ID всех привязанных детей-элементов смартпроцесса с ID 152

$children = \B24\Devtools\Crm\Relation\Manager::searchChildren(\CCrmOwnerType::Quote, 1)
    ->withOne(function (\Bitrix\Crm\ItemIdentifier $identifier) {
        return $identifier; // Вернёт массив из ItemIdentifier
        return $identifier->getEntityId(); // Вернёт массив из ID ItemIdentifier
    });

// Если заменить метод searchChildren на searchParents, то будут искаться родители //
//  Обновление связей //
\B24\Devtools\Crm\Relation\Manager::update(\CCrmOwnerType::Quote, 1, 152, 1)
    ->isParent() // Например если в связи надо отвязать родителя (Предложения) и привязать к другому Предложению
    ->on(\CCrmOwnerType::Quote, 2) // Привязываем к Предложению с ID = 2
    ->replace(); // Замена
// Удаление какой-то одной связи //
\B24\Devtools\Crm\Relation\Manager::deleteOne(\CCrmOwnerType::Quote, 1, 152, 1);

// У Предложения с ID = 1 удаляем все связи со смарт-процессом, у которого ID = 152
\B24\Devtools\Crm\Relation\Manager::deleteWithType(\CCrmOwnerType::Quote, 1, 152);
// Создание связей

// Создаст у Предложения с ID = 1 связь (ребёнка) со смарт-процессом с ID = 152 // 
\B24\Devtools\Crm\Relation\Manager::create(\CCrmOwnerType::Quote, 1, 152, 1);

处理货币字段

$moneyField = '155|USD';
$rateUsdToRub = 93.22;

// либо $money = new \B24\Devtools\Data\MoneyField(155, 'USD');
$money = \B24\Devtools\Data\MoneyField::parse($moneyField)
    ->math(function (&$price) use ($rateUsdToRub) {
        $price = $price * $rateUsdToRub;
    })
    ->setCurrency('RUB')
    ->round(2);

echo (string) $money; // 14449.1|RUB

Highload-块

简化了与 Highload 块的工作。现在 Highload 块被描述为模型

use B24\Devtools\HighloadBlock\ActiveRecord;
use B24\Devtools\HighloadBlock\Fields\Enumeration;
use B24\Devtools\HighloadBlock\Fields\EnumValue;
use B24\Devtools\HighloadBlock\Fields\Field;

class ElementsCatalogHighload extends ActiveRecord
{
    public function getName(): string
    {
        return 'ElementsCatalog';
    }

    public function  getTableName(): string
    {
        return 'elements_catalog';
    }

    public function ruName(): string
    {
        return 'Элементы каталога';
    }

    public function enName(): string
    {
        return 'Elements catalog';
    }
    
    protected function getFields(string $entityId): array
    {
        return [
            new Field(
                entityId:  $entityId,
                fieldName: 'ENUMERATION',
                userTypeId: UserTypeEnum::ENUMERATION,
                multiple: true,
                enum: new Enumeration(
                    [
                        new EnumValue(
                            'Школа43',
                            'SCHOOL43'
                        ),
                    ],
                )
            ),
        ];
    }
}

方法 getFields - 返回 Highload 块的字段列表。默认情况下,Bitrix 创建一个 ID 列,无需指定。

在类的构造函数中传递 3 个必填参数,其他可以不填

class Field
{
    public function __construct(
        private string $entityId,
        private string $fieldName,
        private string|UserTypeEnum $userTypeId,
        private bool $multiple = false,
        private bool $mandatory = true,
        private array $editFormLabel = [],
        private array $listColumnLabel = [],
        private array $listFilterLabel = [],
        private array $errorMessage = [],
        private array $helpMessage = [],
        private ?array $settings = null,
        private ?Enumeration $enum = null
    ) {}
}

在底层,这个类被转换为数组

[
    'ENTITY_ID' => $entityId, // Название сущности
    'FIELD_NAME' => $fieldName, // Название поля. Можно задать без UF_ - он проставится автоматически
    'USER_TYPE_ID' => $userTypeId, // Тип пользовательского поля, можно найти в UserTypeEnum описание всех полей для хайлод блока
    'MULTIPLE' => $multiple, // Множественное поле
    'MANDATORY' => $mandatory, // Обязательность заполнения
    'EDIT_FORM_LABEL' => $editFormLabel ?? $fieldName, // массив языковых сообщений вида array("ru"=>"привет", "en"=>"hello")
    'LIST_COLUMN_LABEL' => $listColumnLabel ?? $fieldName,
    'LIST_FILTER_LABEL' => $listFilterLabel ?? $fieldName,
    'ERROR_MESSAGE' => $errorMessage ?? $fieldName,
    'SETTINGS' => $settings, // массив с настройками свойства зависимыми от типа свойства. Проходят "очистку" через обработчик типа PrepareSettings.
    'ENUM' => $enum,
]

创建和删除 Highload 块

$hl = ElementsCatalogHighload();
$hl->createHL(); // Создание
$hl->dropHL(); // Удаление

Highload 块的事件

在 init.php 中

ElementsCatalogHighload::events()
    ->onAdd(ElementsCatalogEvent::class)
    ->onAfterAdd(ElementsCatalogEvent::class)
    ->onBeforeAdd(ElementsCatalogEvent::class)
    ->onDelete(ElementsCatalogEvent::class)
    ->onAfterDelete(ElementsCatalogEvent::class)
    ->onBeforeDelete(ElementsCatalogEvent::class)
    ->onUpdate(ElementsCatalogEvent::class)
    ->onAfterUpdate(ElementsCatalogEvent::class)
    ->onBeforeUpdate(ElementsCatalogEvent::class)

事件处理器

use B24\Devtools\HighloadBlock\Operation\EventTrait;
use Bitrix\Main\ORM\Event;

class ElementsCatalogEvent
{
    use EventTrait;

    public static function onBeforeAdd(Event $event)
    {
        self::setError($event, 'Ошибка_1');
    }
}

为了方便记录错误,为事件创建了一个 trait B24\Devtools\HighloadBlock\Operation\EventTrait

如果事件名称为 onBeforeAdd,则方法也将是静态的,并命名为 onBeforeAdd。

迁移 Highload 块的字段

继承自 B24\Devtools\HighloadBlock\ActiveRecord 的类有一个必须的方法 getFields,它描述了 Highload 块的字段,方法 migrate 会跟踪这个列表

$hl = ElementsCatalogHighload();
$hl->migrate();

如果从 getFields() 方法中删除了某个字段,它将被跟踪并从数据库中删除。同样,方法也会跟踪 enum 列表的变化

    protected function getFields(string $entityId): array
    {
        return [
            new Field(
                entityId:  $entityId,
                fieldName: 'ENUMERATION',
                userTypeId: UserTypeEnum::ENUMERATION,
                multiple: true,
                enum: new Enumeration(
                    [
                        new EnumValue(
                            value: 'Школа43',
                            xmlId: 'SCHOOL43',
                            def: false, // поле поумолчанию?
                            sort: 500
                        ),
                    ],
                )
            ),
        ];
    }

如果 enum 中添加了另一个 EnumValue,它也将添加到数据库列表中,唯一性由 xmlId 确定。如果从列表中删除了某个 EnumValue,它也将从数据库中删除。如果 EnumValue 的 value 或 def 发生变化,列表的值将更新

方便地在 highload-块中插入/更新记录

记录

$hl = new ElementsCatalogHighload();
$transfer = $hl->getTransfer();
$result = $transfer
    ->set('NAME', 'Имя')
    ->setEnumByXmlId('ENUMERATION', 'SCHOOL43')
    ->saveExistingFile('FILE', 'log.txt') // Все пути будут складываться от $_SERVER['DOCUMENT_ROOT'] . '/'
    ->setDateTime('DATE', new \Bitrix\Main\Type\DateTime()) // второй аргумент такой уже поумолчанию
    ->setBoolean('BOOLEAN', true)
    ->save();

更新记录

$hl = new ElementsCatalogHighload();
$transfer = $hl->getTransfer(id: 1);
$result = $transfer
    ->set('NAME', 'Имя')
    ->save();

在所有 set 方法中,在字段名称前不需要指定 UF_ - 如果没有,它将自动填充。同样,没有必要记住多选字段以将字符串替换为字符串数组,Helper 已经可以做到这一点,它会查看 getFields 方法中描述的字段,如果 $multiple = true,则认为该字段是多选的

$hl = new ElementsCatalogHighload();
$transfer = $hl->getTransfer();
$transfer
    ->setEnumByXmlId('ENUMERATION', 'SCHOOL43')
    ->setEnumByXmlId('ENUMERATION', 'SCHOOL44')

在底层,UF_ENUMERATION 将记录一个包含两个值的数组。