4spacesdk/ci4ormextension

CodeIgniter 4 ORM 扩展


README

Latest Stable Version Total Downloads Latest Unstable Version License PHP Version Require

什么是 CodeIgniter 4 OrmExtension?

OrmExtension 是为 CodeIgniter 4 编写的对象关系映射器,它可以将数据库表映射为易于操作的实体,并完全了解它们之间的关系。OrmExtension 最初基于与 CodeIgniter 2 的相同理念 WanWizard DataMapper,但完全重写以适应 CodeIgniter 4。

安装

步骤 1)

composer require 4spacesdk/ci4ormextension

步骤 2)

创建新文件 app/Config/OrmExtension.php 并添加以下内容

<?php namespace Config;
class OrmExtension {
    public static $modelNamespace = ['App\Models\\'];
    public static $entityNamespace = ['App\Entities\\'];

    /*
     * Provide Namespace for Xamarin models folder
     */
    public $xamarinModelsNamespace          = 'App.Models';
    public $xamarinBaseModelNamespace       = 'App.Models';
}

更新命名空间以符合您的项目。如果模型和实体有多个命名空间,请使用数组。

步骤 3)

将此行添加到您的 app/Config/Events.php 文件中

Events::on('pre_system', [\OrmExtension\Hooks\PreController::class, 'execute']);
Events::on('pre_command', [\OrmExtension\Hooks\PreController::class, 'execute']);

注意!

请记住将 composer 添加到 CodeIgniter 中。检查 app/Config/Constants.php COMPOSER_PATH 是否正确。
请记住添加 /writable/cache-文件夹。除非您拥有许多模型和关系,否则可能会降低性能。

用法

查看 Examples 文件夹以获取灵感。

指南

  1. 实体应使用单数形式命名,例如:User,Role,UserType。
  2. 模型必须以相应的实体命名,并附加 Model,例如:UserModel,RoleModel,UserTypeModel。
  3. 表名应使用实体的复数形式命名,例如:users,roles,user_types。
  4. 连接表应按关系名称的复数形式在字母顺序中命名,例如:roles_users。

模型

基本的 CodeIgniter 4 模型通常看起来像这样

<?php namespace App\Models;
use App\Entities\User;
use CodeIgniter\Model;

class UserModel extends Model {

    protected $table = 'users';
    protected $returnType = User::class;
    protected $allowedFields = ['id', 'name'];

}

OrmExtension 会为您完成这项工作。创建新的模型如下

<?php namespace App\Models;
use OrmExtension\Extensions\Model;

class UserModel extends Model {

}

如果我们遵循指南,那么 OrmExtension 会猜测与 UserModel 相关的表和实体。然而,我们可以在 UserModel 类中添加这些方法来指定表和实体名称

public function getTableName() {
    return "custom_users";
}
public function getEntityName() {
    return "CustomUser";
}

OrmExtension 并不真正关心 $allowedFields。它将通过发送一个 DESCRIBE 语句并使用表中的所有字段来提交。

实体

基本的 CodeIgniter 4 实体通常看起来像这样

<?php namespace App\Entities;
use CodeIgniter\Entity;

class User extends Entity {
    public $id, $name;
}

OrmExtension 并不真正关心我们指定了哪些公共变量。它将在创建 INSERTUPDATE 语句时使用表字段。因此,我们可以让它们保持原样,或者简单地删除它们。创建新的实体如下

<?php namespace App\Entities;
use OrmExtension\Extensions\Entity;

class User extends Entity {

}

关系

每个模型都可以有两种类型的关系: hasOnehasMany。一个用户可以有一个颜色和许多角色。

<?php namespace App\Models;

use OrmExtension\Extensions\Model;

class UserModel extends Model {

    public $hasOne = [
        ColorModel::class,
    ];

    public $hasMany = [
        RoleModel::class
    ];

}

一个角色可以有多个用户。

<?php namespace App\Models;

use OrmExtension\Extensions\Model;

class RoleModel extends Model {

    public $hasMany = [
        UserModel::class
    ];

}

一个颜色可以有多个用户。

<?php namespace App\Models;

use OrmExtension\Extensions\Model;

class ColorModel extends Model {

    public $hasMany = [
        UserModel::class
    ];

}

等效的表

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `color_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) 

CREATE TABLE `roles` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

CREATE TABLE `roles_users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `role_id` int(11) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) 

CREATE TABLE `colors` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(63) DEFAULT NULL,
  PRIMARY KEY (`id`)
) 

这三个模型覆盖了四个表。因为用户和角色之间的关系是多对多,这导致了连接表。我们不需要为连接表创建模型。

真正理解这里发生的事情非常重要。我们得到了三个模型,涵盖了三个实体以及它们之间的关系。我们应该始终指定模型的关系。

查询

当我们有了模型、实体和关系后,我们可以开始使用它们进行一些巧妙的编程!

简单示例

我们可以处理关系而无需考虑连接。选择名为绿色的颜色用户

$userModel = new UserModel();
$users = $userModel
    ->whereRelated(ColorModel::class, 'name', 'green')
    ->find();

选择具有角色管理员和颜色蓝色的用户

$userModel = new UserModel();
$users = $userModel
    ->whereRelated(RoleModel::class, 'name', 'admin')
    ->whereRelated(ColorModel::class, 'name', 'blue')
    ->find();

选择所有用户及其颜色

$userModel = new UserModel();
$users = $userModel
    ->includeRelated(ColorModel::class)
    ->find();

选择具有角色管理员并包括其颜色的用户

$userModel = new UserModel();
$users = $userModel
    ->includeRelated(ColorModel::class)
    ->whereRelated(RoleModel::class, 'name', 'admin')
    ->find(); 

结果

《find()`》的返回值已经更改。《Find》始终返回与调用模型相关的实体类。它永远不会为null或实体数组。这是一个好事——因为现在我们有了一些可以一致工作的内容。实体是可遍历的,因此我们可以在循环中使用它!请查看以下示例

$userModel = new UserModel();
$user = $userModel
    ->where('id', 1)
    ->find(); 
echo json_encode($user->toArray());
{
    "id": 1,
    "name": "Martin"
}
$userModel = new UserModel();
$users = $userModel->find(); 
echo json_encode($users->allToArray());
[
    {
        "id": 1,
        "name": "Martin"
    },
    {
        "id": 2,
        "name": "Kevin"
    }
]

toArray()返回一个包含单个用户属性的数组。allToArray()返回多个用户属性的数组。这些方法非常适合JSON编码。

与实体一起工作

关系可以通过魔法属性访问。这将输出null,因为颜色是一个空的实体。它尚未从数据库中检索。

$userModel = new UserModel();
$users = $userModel->find(); 
foreach($users as $user) {
    echo $user->color->name;
}

我们可以使用include检索颜色

$userModel = new UserModel();
$users = $userModel
    ->includeRelated(ColorModel::class)
    ->find(); 
foreach($users as $user) {
    echo $user->color->name;
}

这将输出实际的颜色名称,因为OrmExtension已经从《find》中预先获取了颜色。

我们也可以之后检索颜色

$userModel = new UserModel();
$users = $userModel->find(); 
foreach($users as $user) {
    $user->color->find();
    echo $user->color->name; 
}

用户可以有多个角色,我们只想访问名为admin的角色。为此,我们必须从实体访问模型以执行where

$userModel = new UserModel();
$user = $userModel->find(1); 
$role = $user->roles->_getModel()
    ->where('name', 'admin')
    ->find();
echo $role->name; // "admin"

深层关系

为此,我们将查看另一个示例。假设一个userbooks,而bookscolor。一本书可以由多个用户共享,但只能有一个颜色。一个颜色可以由多本书共享。

class UserModel {
    public $hasMany = [
        BookModel::class
    ];
}
class BookModel {
    public $hasOne = [
        ColorModel::class
    ],
    public $hasMany = [
        UserModel::class
    ];
}
class ColorModel {
    public $hasMany = [
        BookModel::class
    ];
}

我们想选择所有有绿色书的用户。

$userModel = new UserModel();
$users = $userModel
    ->whereRelated([BookModel::class, ColorModel::class], 'name', 'green')
    ->find();

要访问深层关系,只需将它们放在一个数组中。

软删除

OrmExtension提供了一个扩展的软删除。创建一个名为《Deletion》的模型和实体。
实体

<?php namespace App\Entities;
use OrmExtension\Extensions\Entity;

/**
 * Class Deletion
 * @package App\Entities
 * @property int $id
 * @property int $created_by_id
 * @property string|double $created
 */
class Deletion extends Entity {

}

模型

<?php namespace App\Models;
use OrmExtension\Extensions\Model;

/**
 * Class DeletionModel
 * @package App\Models
 */
class DeletionModel extends Model {

    public $hasOne = [
        
    ];

    public $hasMany = [
        
    ];

}

将名为deletion_id的字段添加到您想要软删除的模型中。OrmExtension将在删除时查找此实体。插入一个Deletion,并将删除实体的关系保存为deletion_id。如果您想记录谁和何时删除了实体,这将很有用。您可以在Deletion-entity上覆盖save()并添加所需的数据。例如:user_id/created_by_idip_addresscreated_at

模型解析器

您可以使用模型解析器生成Swagger文档和TypeScript模型。

$parser = ModelParser::run();
$schemes = $parser->generateSwagger();

$schemes附加到swagger组件,您就有所有模型的文档了。

$parser = ModelParser::run();
$parser->generateTypeScript();

这将生成作为类和接口的typescript模型。在writeable/tmp下找到这些文件。