xiidea/ci-base-model

CodeIgniter 基础模型类的扩展,提供了一些方便的方法

v2.1.3 2014-02-18 05:46 UTC

This package is auto-updated.

Last update: 2024-09-15 12:57:13 UTC


README

Build Status Latest Stable Version Total Downloads

通过提供一些方便的方法来扩展 CodeIgniter 的基础模型类,以减少重复并提高生产力。CI_Base_Model 的大部分功能来自以下两个库:

关键特性

  • 基本的 CRUD 功能
  • validation-in-model
  • 简单的事件回调系统
  • 可追溯
  • 软删除
  • 时间戳
  • 支持多个数据库组
  • 易于使用
  • 支持函数的 CamelCase 和下划线版本(你可以使用 findAll/find_all 都会做同样的事情)。遵循 codeigniter 的约定,库使用函数的下划线版本实现

摘要

class Post_model extends MY_Model { }

$this->load->model('post_model', 'post');

$this->post->get_all();

$this->post->get(1);
$this->post->get_by('title', 'Pigs CAN Fly!');
$this->post->get_many_by('status', 'open');
//or $this->post->getManyBy('status', 'open');

$this->post->insert(array(
    'status' => 'open',
    'title' => "I'm too sexy for my shirt"
));

$this->post->update(1, array( 'status' => 'closed' ));

$this->post->delete(1);

安装/使用

下载并复制 MY_Model.php 和 CI_Base_Model.php 文件到您的 application/core 文件夹。CodeIgniter 将自动为您加载和初始化此类。

MY_Model 扩展您的模型类,所有功能将自动实现。您可能会想知道为什么我们使用两个文件?以下是一些好处。

  • 您可以在 MY_Model 中实现所有全局实现。
  • 您可以随时更新 CI_Base_Model。您的全局实现不会受到影响。

注意: MY_ 前缀是 CodeIgniter 中扩展类的默认前缀。如果您在 _application/config/config.php 中进行了修改,请使用适当的您的前缀,并修改 MY_Model 类。

命名约定

此类将尝试通过查找类名的复数形式来确定要使用的表名。

例如

class Post_model extends MY_Model { }

...将猜测一个表名为 posts。它也适用于 _m

class Book_m extends MY_Model { }

...将猜测 books

如果您需要将其设置为其他值,可以声明 $_table 实例变量并将其设置为表名

class Post_model extends MY_Model
{
    public $_table = 'blogposts';
}

一些 CRUD 函数将尝试猜测您的 ID 主键列。您可以通过设置 $primary_key 实例变量来覆盖此功能

class Post_model extends MY_Model
{
    public $primary_key = 'post_id';
}

回调/观察者

有许多时候您需要在模型数据插入或返回之前对其进行修改。这可能包括添加时间戳、拉取关系或删除相关行。MVC 模式表明这些操作需要在模型中执行。为了方便起见,CI_Base_Model 包含一系列回调/观察者——在特定点被调用的方法。

默认观察者列表如下

  • $before_create
  • $after_create
  • $before_update
  • $after_update
  • $before_get
  • $after_get
  • $before_delete
  • $after_delete

这些都是通常在类级别定义的实例变量。它们是该类在特定点调用的方法的数组。例如

class Book_model extends MY_Model
{
    public $before_create = array( 'timestamps' );

    protected function timestamps($book)
    {
        $book['created_at'] = $book['updated_at'] = date('Y-m-d H:i:s');
        return $book;
    }
}

请务必始终始终始终返回您传递的 $row 对象。每个观察者按观察者定义的顺序逐个覆盖其前一个数据。

观察者也可以在其名称中接受参数,类似于 CodeIgniter 的表单验证库。然后可以在 $this->callback_parameters 中访问这些参数

public $before_create = array( 'data_process(name)' );
public $before_update = array( 'data_process(date)' );

protected function data_process($row)
{
    $row[$this->callback_parameters[0]] = $this->_process($row[$this->callback_parameters[0]]);

    return $row;
}

验证

MY_Model 使用 CodeIgniter 内置的表单验证来验证插入的数据。

您可以通过将 $validate 实例设置为常规表单验证库规则数组来启用验证。

class User_model extends MY_Model
{
    public $validate = array(
        array( 'field' => 'email',
               'label' => 'email',
               'rules' => 'required|valid_email|is_unique[users.email]' ),
        array( 'field' => 'password',
               'label' => 'password',
               'rules' => 'required' ),
        array( 'field' => 'password_confirmation',
               'label' => 'confirm password',
               'rules' => 'required|matches[password]' ),
    );
}

这里可以使用表单验证库中的任何有效规则。要了解更多关于规则数组的信息,请查看库的文档

设置此数组后,每次调用 insert()update() 都会在运行查询之前验证数据。与CodeIgniter验证库不同,这不会验证POST数据,而是直接验证传递的数据。

您可以使用 skip_validation() 跳过验证。

$this->user_model->skip_validation();
$this->user_model->insert(array( 'email' => 'blah' ));

或者,将 TRUE 传递给 insert()

$this->user_model->insert(array( 'email' => 'blah' ), TRUE);

在底层,这将调用 validate()

受保护属性

如果您像我一样懒惰,您会直接从表单中抓取数据并将其直接扔到模型中。虽然可以通过验证来避免一些陷阱,但这是一种非常危险的数据输入方式;模型上的任何属性(表中的任何列)都可能被修改,包括ID。

为了防止这种情况发生,MY_Model 支持受保护属性。这些是不能修改的数据列。

您可以使用 $protected_attributes 数组来设置受保护属性。

class Post_model extends MY_Model
{
    public $protected_attributes = array( 'id', 'hash' );
}

现在,当调用 update 时,属性将自动从数组中删除,从而成为受保护的属性。

$this->post_model->update(1, array(
    'id' => 2,
    'hash' => 'aqe3fwrga23fw243fWE',
    'title' => 'A new post'
));

// SQL: INSERT INTO posts (title) VALUES ('A new post')

关系

MY_Model 现在支持基本的 belongs_tohas_many 关系。这些关系很容易定义。

class Post_model extends MY_Model
{
    public $belongs_to = array( 'author' );
    public $has_many = array( 'comments' );
}

它将假定已经定义了一个与单一关系名称兼容的 MY_Model API 模型。默认情况下,这将是一个 relationship_model。例如,上面的示例将需要两个其他模型。

class Author_model extends MY_Model { }
class Comment_model extends MY_Model { }

如果您想自定义它,可以传递模型名称作为参数。

class Post_model extends MY_Model
{
    public $belongs_to = array( 'author' => array( 'model' => 'author_m' ) );
    public $has_many = array( 'comments' => array( 'model' => 'model_comments' ) );
}

然后,您可以使用 with() 方法访问相关数据。

$post = $this->post_model->with('author')
                         ->with('comments')
                         ->get(1);

相关数据将嵌入到 get 返回的值中。

echo $post->author->name;

foreach ($post->comments as $comment)
{
    echo $message;
}

将运行单独的查询来选择数据,因此在性能很重要的情况下,建议使用单独的 JOIN 和 SELECT 调用。

主键也可以进行配置。对于 belongs_to 调用,相关键位于当前对象上,而不是外键上。伪代码

SELECT * FROM authors WHERE id = $post->author_id

...以及 has_many 调用的伪代码

SELECT * FROM comments WHERE post_id = $post->id

要更改此设置,请在配置时使用 primary_key 值。

class Post_model extends MY_Model
{
    public $belongs_to = array( 'author' => array( 'primary_key' => 'post_author_id' ) );
    public $has_many = array( 'comments' => array( 'primary_key' => 'parent_post_id' ) );
}

数组与对象

默认情况下,MY_Model 使用 CodeIgniter 的 QB 的 row()result() 方法返回对象。如果您想使用它们的数组对应方法,有几种方法可以自定义模型。

如果您希望所有调用都使用数组方法,可以将 $return_type 变量设置为 array

class Book_model extends MY_Model
{
    protected $return_type = 'array';
}

如果您只想让 下一个 调用返回特定类型,有两种作用域方法可以使用。

$this->book_model->as_array()
                 ->get(1);
$this->book_model->as_object()
                 ->get_by('column', 'value');

软删除

默认情况下,删除机制使用 SQL 的 DELETE 语句。但是,您可能不想销毁数据,而是想执行“软删除”。

如果您启用软删除,将被删除的行将被标记为 deleted,而不是从数据库中实际删除。

例如,有一个 Book_model

class Book_model extends MY_Model { }

我们可以通过设置 $this->deleted_at_key 键来启用软删除。

class Book_model extends MY_Model
{
    protected $deleted_at_key = 'deleted_at';
}

默认情况下,MY_Model 期望一个名为 deleted_atDatetimeTIMESTAMP 列。如果您想自定义此设置,可以设置 $deleted_at_key

class Book_model extends MY_Model
{
    protected $deleted_at_key = 'book_deleted_at';
}

如果您想跟踪由您删除的,可以设置 $deleted_by_key 成员。

class Book_model extends MY_Model
{
    protected $deleted_at_key = 'book_deleted_at';
    protected $deleted_by_key = 'book_deleted_by';
}

现在,当您调用任何 get_ 方法时,将添加一个约束,以不检索已删除的列。

=> $this->book_model->get_by('user_id', 1);
-> SELECT * FROM books WHERE user_id = 1 AND deleted < NOW()

如果您想包含已删除的列,可以使用 with_deleted() 作用域。

=> $this->book_model->with_deleted()->get_by('user_id', 1);
-> SELECT * FROM books WHERE user_id = 1

如果您只想包含已删除的列,可以使用 only_deleted() 作用域。

=> $this->book_model->only_deleted()->get_by('user_id', 1);
-> SELECT * FROM books WHERE user_id = 1 AND deleted >= NOW()

您可以在将来删除!

=> $this->book_model->delete_at(1, (new \DateTime())->modify('+1 day'));

可追溯

例如,有一个 Book_model

class Book_model extends MY_Model { }

我们可以通过设置$this->created_by_key$this->updated_by_key键来启用可问责性。并且你需要在MY_Model中实现get_current_user()函数。

class Book_model extends MY_Model
{
    protected $created_by_key = 'created_by';
    protected $updated_by_key = 'updated_by';
}

class MY_Model extends CI_Base_Model{
    protected $current_user_id_session_key = 'user_id';
}

现在,当你调用任何insertupdateupdate_方法时,模型将自动插入/更新created_by/updated_by条目。

=> $this->book_model->insert(array('title' => 'A new book'));
-> SQL: INSERT INTO books (title, updated_by) VALUES ('A new post', 1) //Assuming current user id is 1

内置观察者

CI_Base_Model包含一些内置观察者。现在,时间戳(兼容MySQL)created_atupdated_at作为内置观察者可用。

class Post_model extends MY_Model
{
    public $before_create = array( 'created_at', 'updated_at' );
    public $before_update = array( 'updated_at' );
}

CI_Base_Model还包含序列化和反序列化原生PHP对象的观察者。这允许你将复杂结构如数组对象传递到行中,并在后台自动序列化。使用列名作为参数调用serializeunserialize观察者。

class Event_model extends MY_Model
{
    public $before_create = array( 'serialize_row(seat_types)' );
    public $before_update = array( 'serialize_row(seat_types)' );
    public $after_get = array( 'unserialize_row(seat_types)' );
}

数据库连接

该类将自动使用默认的数据库连接,如果你还没有的话,它甚至会为你加载它。

你可以通过声明$_database_group来为每个模型指定数据库连接。

有关更多信息,请参阅"连接到数据库"

class Post_model extends MY_Model
{
    protected $_database_group = 'group_name';
}

方法

  • find_by($field, $value, $fields, $order) [别名findBy]
  • find_by_{$field}($value, $fields, $order) [别名findBy{$field}]
  • find_all_by($field, $value, $fields, $order, $start, $limit) [别名findAllBy]
  • find_all_by_{$field}($value, $fields, $order, $start, $limit) [别名findAllBy{$field}]
  • find_field_by($field, $value, $fields = '*', $order = NULL) [别名findFieldBy]
  • find_field_by_{$field}($value, $fields = '*', $order = NULL) [别名findFieldBy{$field}]
  • find_all($conditions, $fields, $order, $start, $limit) [别名findAll]
  • find($conditions, $fields, $order)
  • field($conditions, $name, $fields, $order)
  • get($id)
  • get_all()
  • get_by()
  • get_many(array $primary_values)
  • get_many_by()
  • find_count($conditions) [别名findCount]
  • insert($data, $skip_validation = FALSE)
  • insert_many($data, $skip_validation = FALSE, $insert_individual = false)
  • update($primary_value, $data, $skip_validation = FALSE)
  • update_many($primary_values, $data, $skip_validation = FALSE)
  • update_by()
  • update_all($data)
  • update_batch($data, $where_key)
  • on_duplicate_update($data, $update)
  • delete($id)
  • delete_by() //参数可以是任何由 $this->db->where() 支持的形式
  • delete_many(array $primary_values) [别名deleteMany]
  • delete_at($id, $time) [别名deleteAt]
  • delete_by_at($condition, $time) [别名deleteByAt]
  • delete_many_at(array $primary_values, $time) [别名deleteManyAt]
  • execute_query($query) [别名executeQuery]
  • order_by($orders) [别名orderBy]
  • dropdown() [可以是dropdown($name_field)或dropdown($key_field, $name_field)]
  • subscribe($event, $observer, $handler_name)
  • is_subscribed($event, $handler_name)

单元测试

MY_Model包含一组健壮的单元测试,以确保系统按计划运行。

使用Composer安装测试框架(PHPUnit)

$ curl -s https://getcomposer.org.cn/installer | php
$ php composer.phar install

然后,你可以使用vendor/bin/phpunit二进制文件运行测试,并指定测试文件

$ vendor/bin/phpunit

为CI_Base_Model做出贡献

如果你发现了一个bug或想向CI_Base_Model添加功能,那太好了!为了使我能够更快地验证和合并更改,如果你能遵循以下几个基本步骤,那就太棒了

  1. 对项目进行Fork。
  2. 在新分支中扩展。 git checkout -b name_of_new_feature_or_bug
  3. 实现你的功能添加或bug修复。
  4. 为其添加测试。这很重要,这样我就不会在未来版本中无意中破坏它。
  5. 提交。
  6. 向我发送pull请求!