somnambulist/read-models

一个简化版的active-record风格查询层,用于从数据库中检索数据。

4.1.0 2024-03-03 01:53 UTC

README

GitHub Actions Build Status Issues License PHP Version Current Version

Read-Models是Doctrine ORM实体项目的一个配套资源。它们提供了一个仅用于展示目的的active-record风格数据访问层。这允许您的领域对象完全专注于管理数据,而不被展示方面的关注所分散。

为了进一步强调这种紧密的集成,read-models在底层使用DBAL和DBAL类型系统。任何注册的类型都将在模型加载数据时使用,甚至可嵌入的对象也可以重复使用。

请注意,与标准active-record包不同,这个包根本不支持写操作,也不会添加。此包纯粹专注于使用对象/查询构建器读取和查询数据,用于展示层。

内部安排受到了Laravel的Eloquent和其他active-record项目,包括GranadaORM (IdiORM)、PHP ActiveRecord等的极大启发。

支持的功能

  • active-record查询模型
  • 只读 - 不能通过内置方法更改数据库
  • 只读模型 - 没有突变方法,模型加载后不可变
  • 支持属性转换
  • 支持通过属性转换嵌入对象
  • 支持导出为JSON/数组数据(可配置)
  • 关系预加载,包括批量加载
  • 关系(1:1,1:m,m:m,1:m反向)
  • 身份映射
  • 可插拔的属性转换/转换为值对象

要求

  • PHP 8.1+
  • mb_string
  • doctrine/dbal
  • somnambulist/collection

安装

使用composer安装,或从github.com/checkout/pull文件。

  • composer require somnambulist/read-models
  • 使用您的连接映射和任何属性转换器实例化Manager
  • 添加扩展Model类的模型,确保设置表名属性
  • 加载数据:``::find()`

例如

use Doctrine\DBAL\DriverManager;
use Somnambulist\Components\ReadModels\Manager;
use Somnambulist\Components\ReadModels\TypeCasters\DoctrineTypeCaster;

new Manager(
[
    User::class => $conn = DriverManager::getConnection(['url' => 'sqlite://db.sqlite']),
    'default'   => $conn,
],
[
    new DoctrineTypeCaster($conn),
]
);

用法

扩展Somnambulist\Components\ReadModels\Model并添加转换,定义关系,导出等。

class User extends Model
{
    protected string $table = 'users';
}

您可以通过设置属性:`$tableAlias`来添加默认表别名。其他默认值可以通过定义属性来覆盖

class User extends Model
{
    protected string $table = 'tbl_users';
    protected ?string $tableAlias = 'u';
    protected string $primaryKey = 'uuid';
}

注意:属性以类型定义,必须遵循基类中定义的类型。

加载记录

$model = User::find(1);

$results = User::query()->whereColumn('name', 'like', '%bob%')->orderBy('created_at', 'desc')->limit(5)->fetch();

直接访问属性或通过方法调用

$model = User::find(1);

$model->id;
$model->id();
$model->created_at;
$model->createdAt();

您不能设置、删除或更改返回的模型。

您可以像Laravel的Eloquent一样定义属性突变器

class User extends Model
{
    protected function getUsernameAttribute($username)
    {
        return Str::capitalize($username);
    }
}

// user:{username: bob was here} -> returns Bob Was Here

User::find(1)->username();

注意:这些方法应该是`protected`,因为它们期望从加载的模型属性传递当前值。

或者创建虚拟属性,它们在运行时存在

class User extends Model
{
    protected function getAnniversayDayAttribute()
    {
        return $this->created_at->format('l');
    }
}

// user:{created_at: '2019-07-15 14:23:21'} -> "Monday"

User::find(1)->anniversay_day;
User::find(1)->anniversayDay();

或者为了微优化,直接添加方法

class User extends Model
{
    public function anniversayDay()
    {
        return $this->created_at->format('l');
    }
}

// user:{created_at: '2019-07-15 14:23:21'} -> "Monday"

User::find(1)->anniversayDay();

注意:要访问属性通过魔术__get/call,属性名必须是有效的PHP属性/方法名。以数字开头的键(例如)将不起作用。任何虚拟方法/属性应使用`@property-read`标签在类级别文档注释中记录。此外:虚拟方法可以用`@method`标记。

注意:要获取原始属性值,请使用 ->getRawAttribute()。如果找不到属性,它将返回 null,但对于指定的键也可能返回 null。

当返回模型对象集合时,可以根据每个模型自定义返回的集合,以允许对集合进行特定筛选或其他行为。使用类名覆盖 collectionClass 属性。此类必须实现来自 somnambulist/collection 项目的 Collection 协议,并且必须具有 extract()add() 方法。

更多阅读

自动生成的 API 文档位于文档文件夹中。

性能分析

如果您使用 Symfony;使用实体管理器中的标准 Doctrine DBAL 连接将自动确保将所有 SQL 查询添加到分析器中,而无需执行任何其他操作!您可以全面了解已执行的查询、数据绑定等。要进一步了解,请考虑使用应用程序分析器,例如

对于其他框架;由于使用 DBAL,请连接到配置对象并添加一个可以报告给框架分析器的 SQL 记录器实例。

测试套件

测试套件使用名为 "users.db" 的 SQLite 数据库文件,该文件模拟了带有角色、权限、联系人和地址的可能用户设置。在运行测试套件之前,请确保使用:tests/resources/seed.php 生成一些测试数据。此控制台应用程序有几个命令

  • db:create - 构建表结构
  • db:seed - 生成基本记录和 --records=XX 随机记录
  • db:destroy - 删除所有测试数据和表

为了使测试套件运行并能够测试各种关系/预加载等,需要合理数量的测试记录。该套件是在 150 条记录的随机样本上构建的。

DataGenerator 尝试对每个用户随机分配地址、联系人和角色;然而,数据完整性不是目标,只是可用数据。

要运行测试: vendor/bin/phpunit