arrilot/bitrix-models

此包已废弃,不再维护。未建议替代包。

0.8.0 2020-06-19 20:09 UTC

README

Latest Stable Version Total Downloads Build Status Scrutinizer Quality Score

该包不再活跃维护

原因是我们不再在我们的项目中使用Bitrix。如果您对此项目感兴趣并希望维护它 - 分支它并在本存储库中创建一个Issue,以便我们将链接放在这里。

分支

Bitrix模型

简介

此包将Model Layer引入Bitrix。此层逻辑上由两部分组成

  1. 为Bitrix实体创建的模型(以下将称为“Bitrix模型”),通过Bitrix的API(如CIBlockElement等)工作,并作为其上层构建。从外部来看,这个上层构建类似于Eloquent
  2. 用于任意表的模型,通过illuminate/database(尤其是Eloquent)工作。

安装

  1. composer require arrilot/bitrix-models
  2. init.php中注册包 - Arrilot\BitrixModels\ServiceProvider::register();

使用Bitrix模型

以下模型可用于继承

Arrilot\BitrixModels\Models\ElementModel
Arrilot\BitrixModels\Models\SectionModel
Arrilot\BitrixModels\Models\UserModel
Arrilot\BitrixModels\Models\D7Model

以下我们将以ElementModel(信息块元素的模型)为例,其他实体的API几乎相同。

ElementModel完全支持第二版信息块(存储属性在单独的表中)。第一版可能由于CIBlockElement::GetList()的工作方式而无法正常工作。最大的问题是:如果信息块有多个属性,那么limit()、take()和first()的请求将无法正常工作,并且会得到比需要的更少的元素,并且不会得到完整的多个属性集合。如果您仍然打算使用第一版信息块与ElementModel一起使用,则必须在模型类中设置const IBLOCK_VERSION = 1;

创建一个商品信息块的模型。

<?php

use Arrilot\BitrixModels\Models\ElementModel;

class Product extends ElementModel
{
    /**
     * Corresponding iblock id.
     *
     * @return int
     */
    const IBLOCK_ID = 1;
}

要使用模型,只需在常量中设置信息块的ID。对于用户来说,这也不是必需的。

如果您不想绑定到信息块ID,可以在模型中重写public static iblockId()方法并从该方法获取信息块ID,例如按代码。这提供了更大的灵活性,但您可能需要额外的数据库查询。

我们将使用我们的Product类作为静态和动态上下文。

添加产品

// $fields - массив, аналогичный передаваемому в CIblockElement::Add(), но IBLOCK_ID в нём можно не указывать.
$product = Product::create($fields);

注意:如果在以后使用中使用了$product字段,建议立即使用新的数据库查询更新对象。这是由于CIblockElement::Add()和CIblockElement::GetList()中的字段格式在100%上不匹配。这样做的方法是

$product = Product::create($fields)
$product->refresh();

更新

// вариант 1
$product['NAME'] = 'Новое имя продукта';
$product->save();

// вариант 2
$product->update(['NAME' => 'Новое имя продукта']);

不查询数据库进行模型实例化。

对于一些操作,不需要从数据库获取信息,只需要对象的ID。在这种情况下,只需实例化模型对象,并在构造函数中传递标识符。

$product = new Product($id);

//теперь есть возможно работать с моделью, допустим
$product->deactivate();

从数据库获取对象字段

$product = new Product($id);

// метод `load` обращается к базе, только если информация еще не была получена.
$product->load();

// Если мы хотим принудительно обновить информацию из базы даже если она уже была получена ранее
$product->refresh();

// После любого из этих методов, мы можем работать с полученными полями (`echo $product['CODE'];`)

//Для текущего пользователья есть отдельный хэлпер
$user = User::current();
// В итоге мы получаем инстанс User с заполненными полями. 
// Сколько бы раз мы не вызывали `User::current()` в рамках работы скрипта, запрос в базу происходит только один раз - первый.
// `User::freshCurrent()` - то же самое, но получает данные из базы каждый раз.

描述的方法将数据库中的数据保存在类模型实例内部。模型对象实现了ArrayAccess,因此可以像处理数组一样处理它们。

$product->load();
if ($product['CODE'] === 'test') {
    $product->deactivate();
}

将模型转换为数组/json。

$array = $product->toArray();
$json = $product->toJson();

默认情况下,模型的所有字段都可在数组中访问,这并不总是希望的。模型有特殊的属性protected $visible = [];protected $hidden = [];,可以通过这些属性来构建白名单/黑名单字段,以将模型转换为数组/json。

获取数据库信息

使用模型的最常见场景是从数据库获取元素/列表。用于构建查询的是“Fluent API”,它内部使用标准的Bitrix API。

开始构建查询使用静态方法::query()。此方法返回一个查询构建器对象(ElementQuerySectionQueryUserQuery),通过它来构建查询链。

简单示例

$products = Product::query()->select('ID')->getList();

实际上,这个形式主要是为了理解,有一个更方便的版本,它使用__callStatic将控制权传递给查询对象。

$products = Product::select('ID')->getList();

任何查询链都必须以以下方法之一结束

  1. ->getList() - 获取对象集合(参见 https://laravel.net.cn/docs/master/collections)。默认情况下,每个元素的键是其ID。
  2. ->getById($id) - 根据其ID获取对象。
  3. ->first() - 获取符合查询参数的一个(第一个)对象。
  4. ->count() - 获取对象数量。
  5. ->paginate() 或 ->simplePaginate() - 获取分页列表及其元数据(参见 https://laravel.net.cn/docs/master/pagination
  6. 针对单个实体的方法:->getByLogin($login)->getByEmail($email) - 获取具有给定登录名/email的第一个用户。->getByCode($code)->getByExternalId($id) - 获取第一个元素或分类信息,通过CODE/EXTERNAL_ID

管理选择

  1. ->sort($array) - 等同于 $arSortCIBlockElement::GetList的第一个参数)

示例

->sort(['NAME' => 'ASC', 'ID' => 'DESC'])

->sort('NAME', 'DESC') // = ->sort(['NAME' => 'DESC'])

->sort('NAME') // = ->sort(['NAME' => 'ASC'])

  1. ->filter($array) - 等同于 $arFilter
  2. ->navigation($array)
  3. ->select(...) - 等同于 $arSelect

示例

->select(['ID', 'NAME'])

->select('ID', 'NAME')

select() 支持两个附加值 - 'FIELDS'(选择所有字段),'PROPS'(选择所有属性)。对于用户也可以指定 'GROUPS'(在查询中添加用户组)。对于 ElementModel 的默认值是 ['FIELDS', 'PROPS']

  1. ->limit($int)->take($int)->page($int)->forPage($page, $perPage) - 用于导航

Fetch和GetNext

默认情况下,在遍历从数据库获取的元素/部分/用户时,使用高效的方法 ->Fetch()。与 ->GetNext() 不同,它不会将数据转换为html安全格式,也不会将 DETAIL_PAGE_URL、SECTION_PAGE_URL 转换为元素和类别的真实网址。如果查询结果需要这些转换,则可以切换到该方法。

  1. 可以立即切换整个模型,只需为其设置属性。

        public static $fetchUsing = 'GetNext';
    
        // полная форма, если нужно менять параметры.
        public static $fetchUsing = [
            'method' => 'GetNext',
            'params' => [true, true],
        ];
  2. 也可以只为单个请求切换。

         Products::query()->filter(['ACTIVE' => 'Y'])->fetchUsing('GetNext')->getList()`
         // вместо строки `'GetNext'` можно как и в первом случае использовать массив.

一些额外的注意事项

  1. 为了限制选择,添加了别名 limit($value)(对应于 nPageSize)和 page($num)(对应于 iNumPage)。
  2. 在API的一些地方,与Bitrix本身相比更友好。例如,在按用户筛选时,不一定要使用 'GROUP_IDS'。在传递 'GROUP_ID'(这正是Bitrix需要的键,例如在创建用户时)或 'GROUPS' 时,结果将是相同的。
  3. 在创建或更改信息块元素和部分时,Bitrix会重建搜索索引,并允许在特定的 Add/Update 调用中跳过重建,以提高性能。在模型中,您可以通过直接在模型类中设置 protected static $updateSearch = false; 或在添加/更新之前调用单独的静态方法 Product::setUpdateSearch(false) 来实现相同的效果。
  4. 对于 CIBlockElement::Add/Update,也可以用相同的方式管理 $bWorkFlow 和 $bResizePictures 标志。

查询作用域

可以通过在模型中添加 "query scopes" 来扩展查询构建器。为此,需要创建一个以 scope 开头的方法。

包中已经存在一个 "query scope" 的示例。

    /**
     * Scope to get only active items.
     *
     * @param BaseQuery $query
     *
     * @return BaseQuery
     */
    public function scopeActive($query)
    {
        $query->filter['ACTIVE'] = 'Y';
    
        return $query;
    }

...

$products = Product::filter(['SECTION_ID' => $secId])
                    ->active()
                    ->getList();

在 "query scopes" 中也可以传递额外的参数。

    /**
     * @param ElementQuery $query
     * @param string|array $category
     *
     * @return ElementQuery
     */
    public function scopeFromSectionWithCode($query, $category)
    {
        $query->filter['SECTION_CODE'] = $category;

        return $query;
    }

...
$users = Product::fromSectionWithCode('sale')->getList();

这些作用域已经存在于包中,可以开始使用。

停止操作

有时需要从查询作用域中停止数据库选择。为此,只需返回 false 即可。示例

    public function scopeFromCategory($query, $category)
    {
        if (!$category) {
            return false;
        }
        
        $query->filter['SECTION_CODE'] = $category;

        return $query;
    }
...

结果不会对数据库进行查询 - getList() 将返回空集合,getById() 将返回 false,而 count() 将返回 0。

也可以通过手动调用方法 ->stopQuery() 达到相同的效果。

查询缓存

对于所有上述Bitrix模型,都有一个简单的内置缓存机制。只需在调用链中添加 ->cache($minutes)-> 即可,然后数据库选择的结果将缓存指定的分钟数。示例:$products = Products::query()->cache(30)->filter(['ACTIVE' => 'Y'])->getList() 在幕后,缓存使用的是d7 Bitrix的标准机制。缓存键取决于模型和所有查询参数。

访问器

有时需要在从数据库中选择数据并从模型获取数据之间修改数据。为此,使用访问器。同样,对于 "query scopes",要添加访问器,需要向相应的模型添加方法。

方法命名的规则是 $methodName = "get".camelCase($field)."Attribute"。示例

    public function getXmlIdAttribute($value)
    {
        return (int) $value;  
    }
    
    // теперь в $product['XML_ID'] всегда будет целочисленное значение
    

需要谨慎使用此方法,因为原始值将不可用。

也可以为不存在的(虚拟)字段创建访问器,例如

    public function getFullNameAttribute()
    {
        return $this['NAME']." ".$this['LAST_NAME'];
    }
    
    ...
    
    echo $user['NAME']; // John
    echo $user['LAST_NAME']; // Doe
    echo $user['FULL_NAME']; // John Doe

为了使这样的虚拟访问器在 toArray() 和 toJson() 中显示,必须在模型的 $appends 字段中显式指定它们。

    protected $appends = ['FULL_NAME'];

语言访问器

对于多语言网站,通常的做法是为每种语言创建一个属性,例如,UF_TITLE_RU,UF_TITLE_BY。在这种情况下,可以为这样的字段创建一个访问器。

// используем далее $section['UF_TITLE'];
public function getUfTitleAttribute()
{
    return $this['UF_TITLE_' . strtoupper(LANGUAGE_ID)];
}

// используем далее $element['PROPERTY_TITLE'];
public function getPropertyTitleAttribute()
{
    return $this['PROPERTY_TITLE_' . strtoupper(LANGUAGE_ID) . '_VALUE'];
}

由于这些访问器类型相同并且有污染模型的不良特性,因此可以为他们使用特殊的简短语法。

class Product extends ElementModel
{
    protected $languageAccessors = [
        'PROPERTY_TITLE',
        'PROPERTY_FOO'
    ];
}

模型事件(Model Events)

事件允许在模型的生命周期中的不同点插入代码。例如,在创建元素时自动设置字符代码。模型事件不使用Bitrix的事件模型(无论是旧内核还是D7),仅涉及模型内部发生的事情。使用Bitrix事件覆盖了更多用例。

事件处理器通过在模型类中重定义相应的方法来设置。

class News extends ElementModel
{
    /**
     * Hook into before item create or update.
     *
     * @return mixed
     */
    protected function onBeforeSave()
    {
        $this['CODE'] = CUtil::translit($this['NAME'], "ru");
    }

    /**
     * Hook into after item create or update.
     *
     * @param bool $result
     *
     * @return void
     */
    protected function onAfterSave($result)
    {
        //
    }
}

其他事件处理器的签名与上面所述相同。

可用的事件列表

  1. onBeforeCreate - 在添加记录之前
  2. onAfterCreate(bool $result) - 在添加记录之后
  3. onBeforeUpdate - 在更新记录之前
  4. onAfterUpdate(bool $result) - 在更新记录之后
  5. onBeforeSave - 在添加或更新记录之前
  6. onAfterSave(bool $result) - 在添加或更新记录之后
  7. onBeforeDelete - 在删除记录之前
  8. onAfterDelete(bool $result) - 在删除记录之后

如果从onBefore...()处理器返回return false;,则后续操作将被取消。在处理器中可以通过当前模型的属性获取额外信息。例如,在onBefore...()处理器中,可以通过$this->fields访问所有字段。在所有onAfter...()中,可以通过$this->eventErrors访问错误数组;在onBeforeUpdate()onBeforeSave()中,可以通过$this->fieldsSelectedForSave访问要更新的字段的键数组。

D7 Model

与之前模型相比,《D7Model》有些特别。它使用D7作为后端而不是旧的GetList等,可以通过它来处理D7的普通实体和块。

块示例

class Subscriber extends D7Model
{
    public static function tableClass()
    {
        $hlBlock = HighloadBlockTable::getRowById(1);
    
        return HighloadBlockTable::compileEntity($hlBlock)->getDataClass();
    }
}

获取块类的逻辑可以是任何形式,但重要的是不要忘记编译它,否则它将无法工作。最方便的方法是使用辅助包https://github.com/arrilot/bitrix-iblock-helper/。有了它,我们得到以下结果

class Subscriber extends D7Model
{
    public static function tableClass()
    {
        return highloadblock_class('app_subscribers');
    }
}

如果我们不处理块,而是处理完整的D7 ORM实体,那么我们只需在此方法中返回该实体的完整类名即可。D7Model的调用链和命名方法与之前模型相同。我们传递给这些方法的任何内容都将传递到D7。

获取所有名为John的订阅者的示例,并缓存5分钟

$subscribers = Subscriber::query()->cache(5)->filter(['=NAME'=>'John])->getList();

完整的方法列表如下

/**
 * static int count()
 *
 * D7Query methods
 * @method static D7Query runtime(array|\Bitrix\Main\Entity\ExpressionField $fields)
 * @method static D7Query enableDataDoubling()
 * @method static D7Query disableDataDoubling()
 * @method static D7Query cacheJoins(bool $value)
 *
 * BaseQuery methods
 * @method static Collection getList()
 * @method static D7Model first()
 * @method static D7Model getById(int $id)
 * @method static D7Query sort(string|array $by, string $order='ASC')
 * @method static D7Query order(string|array $by, string $order='ASC') // same as sort()
 * @method static D7Query filter(array $filter)
 * @method static D7Query addFilter(array $filters)
 * @method static D7Query resetFilter()
 * @method static D7Query navigation(array $filter)
 * @method static D7Query select($value)
 * @method static D7Query keyBy(string $value)
 * @method static D7Query limit(int $value)
 * @method static D7Query offset(int $value)
 * @method static D7Query page(int $num)
 * @method static D7Query take(int $value) // same as limit()
 * @method static D7Query forPage(int $page, int $perPage=15)
 * @method static \Illuminate\Pagination\LengthAwarePaginator paginate(int $perPage = 15, string $pageName = 'page')
 * @method static \Illuminate\Pagination\Paginator simplePaginate(int $perPage = 15, string $pageName = 'page')
 * @method static D7Query stopQuery()
 * @method static D7Query cache(float|int $minutes)
 */

有关详细信息,请参阅vendor/arrilot/bitrix-models/src/Models/D7Model.phpvendor/arrilot/bitrix-models/src/Queries/D7Query.php

模型之间的关系(Relations)

除了处理单独的Bitrix模型之外,还可以在模型之间建立关系,这使得它们可以通过主要数据对象轻松访问。例如,商品与商品问题相关联。通过声明这种关系,您可以使用表达式$product->questions获取模型问题对象,它返回问题的信息,以Question类(BaseBitrixModel的子类)对象的集合形式。

声明关系

/**
 * Class Product
 *
 * @property Brand $brand
 * @property ProductQuestion $questions
 * @property Storage $storages
 */
class Product extends ElementModel
{
    ...
    
    /**
     * ID Brand записан в текущую модель в свойтво PROPERTY_BRAND_VALUE (не множественное)
     * (у товара может быть только один бренд, но у бренда много товаров)
     */
    public function brand()
    {
        return $this->hasOne(Brand::class, 'ID', 'PROPERTY_BRAND_VALUE');
    }
    
    /**
     * У ProductQuestion в свойтве PROPERTY_PRODUCT_VALUE записан ID текущей модели
     * (у товара может быть много вопросов, но вопрос относится только к одному товару)
     *
     * Но это будет так же работать, если PROPERTY_PRODUCT_VALUE будет множественным
     */
    public function questions()
    {
        return $this->hasMany(ProductQuestion::class, 'PROPERTY_PRODUCT_VALUE', 'ID');
    }
    
    /**
     * ID Storage записан в текущую модель в свойтво PROPERTY_STORAGE_VALUE (множественное)
     * (у товара может быть много складов, на складе может быть много товаров)
     */
    public function storages()
    {
        return $this->hasMany(Storage::class, 'ID', 'PROPERTY_STORAGE_VALUE');

    }
}

关系名称对大小写敏感。

在声明关系时,您必须指定以下信息

  • 关系的数量:通过调用 hasMany() 方法或 hasOne() 方法来指定。
  • 关联类名称:作为 hasMany() / hasOne() 方法的第一个参数指定。
  • 两种数据类型之间的关系:第二个参数是外部模型中的字段,第三个参数是内部模型中的字段(默认为 ID)。
  • 与其他 ORM 不同,多对多关系不使用中间(pivot)表。相反,使用 Bitrix 的多属性。

访问关联数据

声明关系后,您可以通过关系名称访问关联数据。访问是通过对象的属性完成的。属性名称 = 关联方法名称(但去掉方法括号)

$product = Product::getById(1);

// В этот момент используются магические методы и выполняются sql запросы в БД за данными.
$product->brand; // Объект класса Brand
$product->questions; // Collection объектов класса ProductQuestion

// Запросы в базу выполняются лишь один раз. При повторном обращении к переменной возвращаются данные получененные при первом запросе. 
$product->brand;
$product->questions;

延迟和贪婪加载

上面的示例使用了延迟加载(在首次访问时加载数据)。当处理数据数组时,会收到循环查询,产生 n + 1 问题。

$products = Product::getList();

foreach($products as $product) {
    // Выполняется запрос
    $product->brand;
}

为了避免这种情况,需要使用贪婪加载

// Выполняется один дополнительный запрос который получит все бренды для всех полученных продуктов.
$products = Product::query()->with('brand')->getList();

foreach($products as $product) {
    // Запрос не выполняется
    $product->brand;
}
  • with 方法可以多次调用。
  • 它接受一个字符串作为参数 - 关联名称或多个字符串/字符串数组 ->with('brand', 'questions')/->with(['brand', 'questions'])
  • 您可以指定嵌套关系 ->with('questions.answers')(在这种情况下,将立即加载问题和每个问题的答案列表。总共 3 个请求 - 商品,问题,答案)。
  • 可以通过回调来修改查询。例如,为了只加载活动问题,并为它们加载答案
->with([
    'questions' => function ($query) {
        $query->filter(['ACTIVE' => 'Y'])
    },
    'questions.answers'
])

使用 Eloquent 模型

包的第二部分是 ORM Eloquent 的集成,用于 Bitrix 中的用户表,即手动创建的表,而不是与系统一起提供的表。实际上,这是直接向数据库查询、D7 ORM 和此包中的 D7Model 的替代方案。

通过 Eloquent,不仅可以处理用户表,还可以处理 Highload 块,这非常方便。在这种情况下,我们与 Highload 块的表一起工作,而无需使用 Bitrix 的任何 API。

值得注意的是,与 Bitrix 不同,Eloquent 使用 PHP 扩展访问 mysql,而不是 mysql/mysqli,而是 PDO。这意味着

  1. 必须安装和配置 PDO
  2. 将创建两个数据库连接。

注意:问题:为什么在包中包含 Eloquent,如果已经有 D7Model?哪个更好?回答:选择取决于项目条件和个人偏好。Eloquent 比Bitrix 和 D7Model 中所有内容都更方便且功能更强大,例如,它提供了通过中间表进行的完整模型之间的关联等。另一方面,这是一个较大的外部依赖,有它自己的要求

缺点

安装

首先,需要安装另一个依赖项 - composer require illuminate/database 之后,在 init.php 中添加一行 - Arrilot\BitrixModels\ServiceProvider::registerEloquent(); 现在可以创建 Eloquent 模型,继承自 EloquentModel

<?php

use Arrilot\BitrixModels\Models\EloquentModel;

class Product extends EloquentModel
{
    protected $table = 'app_products';
}

如果表名为 products(类名称的复数形式),则可以省略 protected $table = 'products'; - 这是 Eloquent 的标准行为。不同之处在于

  1. 主键是 ID,而不是 id
  2. 用于创建和更新记录的字段称为 UF_CREATED_ATUF_UPDATED_AT,而不是 created_atupdated_at

如果您决定不在表中添加 UF_CREATED_AT 和 UF_UPDATED_AT 字段,则需要在模型中设置 public $timestamps = false;

通过 Eloquent 使用高负载块

假设我们创建了一个名为 Brands 的高负载块,为它指定了 brands 表,并添加了 UF_NAME 属性。那么它的模型类将如下所示

<?php

use Arrilot\BitrixModels\Models\EloquentModel;

class Brand extends EloquentModel
{
    public $timestamps = false;
}

要向其中添加新记录,只需要以下代码

$brand = new Brand();
$brand['UF_NAME'] = 'Nike';
$brand->save();

// либо даже такого если настроены $fillable поля.
$brand = Brand::create(['UF_NAME' => 'Nike']);

要充分利用 Eloquent 模型,重要的是要熟悉该 ORM 的官方文档 (链接再次)

最后要注意的是,尽管 Bitrix 模型和 Eloquent 模型的 API 非常相似(这在很大程度上是因为 Bitrix 模型是在 Eloquent 的影响下开发的),但它们确实是不同的事物,并且内部是完全独立的。不能例如创建 Eloquent 模型和 Bitrix 模型的关联。

Highload 块和 Eloquent 模型的多个属性

高负载块中的多个属性实现得有些巧妙。数据存储在两个地方

  1. 直接在 Highload 块的表中以序列化形式。
  2. 在用于该属性的一个附加表中。幸运的是,该包能够很好地解决这个问题。添加多个属性时,只需将此属性的代码添加到模型的 $multipleHighloadBlockFields 字段数组中即可。例如 public $multipleHighloadBlockFields = ['UF_SOME_MULTIPLE_FIELD']; 然后
  3. $model['UF_SOME_MULTIPLE_FIELD'] 将返回反序列化的数组
  4. 要添加/更新字段值,也只需将数组放在 $model['UF_SOME_MULTIPLE_FIELD'] 中,无需手动序列化。
  5. 添加/更新字段值时,更改将自动应用于辅助表。无需手动更改。要使最后一点生效,需要安装额外的依赖项 - composer require illuminate/events。没有这个依赖项,辅助表将不会更新。关于它的更多信息将在下一段中介绍。

Eloquent 模型中的事件

Eloquent 有所谓的 模型事件 / Model events,它允许在模型的某个时刻进行干预。总的来说,它与 Bitrix 的 OnBeforeIblockElementUpdate 等事件非常相似。如果您需要它们,则还需要安装 illuminate/databaseilluminate/events 依赖项。

composer require illuminate/events

查询构建器

在连接 Eloquent 时,我们免费获得 Laravel 的 Query Builder,它位于 https://laravel.net.cn/docs/master/queries,它非常有用,如果需要直接与数据库交互而无需通过模型层进行抽象。它比 $DB->Query() 和其他方法更方便、更安全。

通过全局可访问的类 DB 进行构建器的工作。例如,向 HL 块添加品牌元素将如下所示

DB::table('brands')->insert(['UF_NAME' => 'Nike']);

分页导航 (pagination)

Bitrix-模型和Eloquent-模型都支持->paginate()->simplePaginate()(参见https://laravel.net.cn/docs/master/pagination)。为了然后通过->links()显示分页导航,需要

  1. 安装https://github.com/arrilot/bitrix-blade/
  2. 将默认视图从https://github.com/laravel/framework/tree/master/src/Illuminate/Pagination/resources/views复制到local/views/pagination

之后,可以修改这些视图或创建新的视图。

连接到多个数据库,详细配置连接。

默认情况下,连接到数据库使用的是与Bitrix一起工作的标准配置。例如,它可以看起来像这样(文件.settings.php):

'connections' => [
    'value' => [
        'default' => [
            'className' => '\\Bitrix\\Main\\DB\\MysqliConnection',
            'host' => 'localhost',
            'database' => 'db',
            'login' => 'login',
            'password' => 'password',
            'options' => 2,
        ],
    ],
    'readonly' => true,
]

为了能够使用Eloquent的全部功能,需要在.settings.php文件中添加一个描述连接的数组bitrix-models.illuminate-database

[
    ...
    'bitrix-models.illuminate-database' => [
        'value' => [
                'default' => 'mysql',
                'connections' => [
                    'mysql' => [
                        'driver' => 'mysql',
                        'url' => getenv('DB_MYSQL_URL'),
                        'host' => getenv('DB_MYSQL_HOST'),
                        'port' => getenv('DB_MYSQL_PORT'),
                        'database' => getenv('DB_MYSQL_DATABASE'),
                        'username' => getenv('DB_MYSQL_USERNAME'),
                        'password' => getenv('DB_MYSQL_PASSWORD'),
                        'unix_socket' => getenv('DB_MYSQL_SOCKET'),
                        'charset' => 'utf8',
                        'collation' => 'utf8_unicode_ci',
                        'prefix' => '',
                        'prefix_indexes' => true,
                        'strict' => false,
                        'engine' => null,
                        'options' => [],
                    ],
                    'mysql_2' => [
                        ...
                    ],
                ],
            ],
        'readonly' => true,
    ],
]

重要!如果指定了bitrix-models.illuminate-database数组,那么Eloquent的数据库连接配置只从这个数组中获取,而标准配置将被忽略。

更多配置连接的示例(connections):https://github.com/laravel/laravel/blob/5.7/config/database.php

D7Model/EloquentModel中的元素活动状态

在Bitrix的信息块中有一个ACTIVE = 'Y'/'N'字段,根据这个字段进行过滤非常常用。在HiLoad块和自定义表中默认没有这样的字段,但该包提供了一个帮助创建此类功能的trait。它是如何工作的

  1. 在表/HiLoad块中添加字段UF_DEACTIVATED_AT,类型为datetime。

  2. 在D7Model/EloquentModel中添加trait use \Arrilot\BitrixModels\Models\Traits\DeactivationTrait;

  3. 现在在模型中可用的方法有

    3.1. $model->deactivate()$model->activate() - 在数据库中禁用或激活元素。

    3.2. $model->markForDeactivation()$model->markForActivation() - 与上面相同,但只更改php变量,不执行->save()。如果需要激活时在表中进行其他更改,并且不想执行额外的数据库查询,这很有用。

    3.3. 范围->active()->deactivated()。例如SomeD7Model::query()->active()->getList()