slaxweb / ci-basemodel
CodeIgniter 的 BaseModel
Requires
- php: >=5.3.0
Requires (Dev)
- mockery/mockery: ~0.9
- phpunit/phpunit: ~4.2
README
CodeIgniter 的基础模型,帮助您在模型中执行数据库操作。它自动猜测表名,节省您软删除等麻烦。BaseModel 也被BaseController使用。
BaseModel 的想法来自 Jamie Rumbelow 的 基础模型,并进行了一些添加和修改。如果您遇到问题或有疑问/想法,请在此处提交 GitHub 上的工单。
这仍然处于开发阶段,但已准备好投入生产。它只经过 mySQL 测试,当时可能只能与 mySQL 一起工作,尽管已添加了对其他驱动程序的支持,但这是实验性的。
目录
安装
目前安装的最简单方法是使用 composer,或者通过安装版本 0.2+ 的 BaseController,其中将 BaseModel 列为需求。只需在项目根目录中创建 composer.json 文件
{
"require": {
"slaxweb/ci-basemodel": "~0.3"
}
}
然后运行 composer.phar install。完成后,在 application/config/config.php 配置文件中启用 composer 自动加载器。
使用 BaseModel
BaseModel 意味着要由您的模型扩展,因此,您应从 \SlaxWeb\BaseModel\Model 扩展,而不是从 CI_Model 扩展
class Some_model extends \SlaxWeb\BaseModel\Model
有了这些,您的 BaseModel 就可以使用了。
作为替代,您还可以从 MY_Model 扩展,并让 MY_Model 扩展 BaseModel。
属性
BaseModel 提供了您可以设置的下一组属性
- table - 模型的表,尽管 BaseModel 会自动从其名称中猜测表名。
- tablePrefix - 表前缀,如果您为每个模型使用特殊的前缀,请在此设置
- primaryKey - 默认为 "id",如果您使用其他内容作为主键,请在此设置
- keyType - 键的类型,自增(默认),UUID 键,或您用于生成主键的特定 PHP 或自定义函数
- keyFunc - 如果您使用一个函数来生成主键,请在此处分配,接受可调用类型
- keyFuncParams - keyFunc函数使用的参数
- softDelete - 使用软删除,默认为“硬删除”。有3个选项,软删除状态列,软删除标记列,硬删除
- deleteCol - 如果使用软删除标记列,请在此处定义它,默认为“deleted”
- statusCol - 如果使用软删除状态列,请在此处定义该列,默认为“status”
- deleteStatus - 为状态列设置已删除的状态值,默认为“deleted”
- rules - 验证规则
- where - 一个自定义的where字符串
- whereBinds - 如果使用自定义的where字符串,并且您想将参数绑定到where字符串中,可以将这些参数添加到该属性的数组中
目前BaseModel提供了一个回调函数beforeInit,此回调在BaseModel初始化之前调用。
表名
定义表名有3种方式,首先是在您的模型中定义一个公共属性table,在构造函数中将表名传递给BaseModel __construct 方法,或者让BaseModel尝试并确定您的表名。
猜测表名
在猜测表名时,BaseModel会取您的模型类名,删除_model或_m后缀,将剩余部分复数化,并将所有内容转换为小写字母。所以例如User_model变成users。
配置常量
BaseModel提供了一个\SlaxWeb\BaseModal\Constants类用于配置软删除和主键类型。要在控制器中使用,最佳方式是在声明模型之前使用该类。
<?php use \SlaxWeb\BaseModel\Constants as C; class Test_model extends \SlaxWeb\BaseModel\model { }
如果您需要更改软删除设置或主键类型,只需使用这些常量即可
- DELETEHARD - 硬删除
- DELETESOFTMARK - 使用删除列标记已删除的行
- DELETESOFTSTATUS - 使用状态列标记已删除的行
- PKEYAI - 自增主键
- PKEYUUID - 由数据库中的UUID()生成的主键
- PKEYFUNC - 由PHP函数或您的自定义函数生成的主键
- PKEYNONE - 无主键
数据库操作
插入数据
要插入数据,BaseModel提供了一个insert方法,该方法接受要插入的数据作为数组。
$this->insert(array("column" => "value"));
此方法将首先尝试验证数据,如果您已设置rules属性并且未设置跳过验证。
出错时,方法将返回一个Error对象,或成功时返回true。
获取数据
您可以通过主键、您自己的where参数或获取表中的一切来获取数据。为此,有两种方法,get和getBy。要按主键检索一行,请使用具有主键值作为输入参数的get方法。
// retrieves row with primary key value 123 $this->get(123);
如果您想获取所有内容,只需在get方法中省略主键值。要基于您自己的where语句获取数据,您有两个选项,要么设置BaseModel的where属性,要么将“where”数组传递给getBy方法。
$this->getBy(array("column" => "value"));
此方法还提供了选择特定列的方法。您可以将列数组作为第二个参数传递,或作为字符串传递,就像您在SELECT SQL语句中使用它们一样。
所有get方法都返回Result对象。
更新数据
除了获取数据外,更新也提供了3种方式,按主键更新、按您自己的where语句更新或更新表中的所有内容。这两个方法分别是update和updateBy。它们的工作方式几乎与获取数据相同,除了您需要提供要更新的数据数组作为第一个参数,以及主键值或您的where语句作为第二个参数。
$this->update(array("column" => "value"), 123);
这将更新名为“column”的列,其中主键值为123。
要使用自己的 WHERE 语句,您需要将其作为数组或与 SQL 语句中使用相同的方式传递给 updateBy 方法。
$this->updateBy(array("column" => "value"), array("whereColumn" => "whereValue"));
更新操作首先会尝试验证数据,如果设置了规则并且您没有标记跳过验证。
发生错误时,方法将返回 错误 对象。
删除数据
对于删除操作,您仍然有两种方法:delete 和 deleteBy,并且同样,您可以通过主键值、自己的 WHERE 语句或删除所有内容来进行删除。如果您正在使用按状态或已删除列进行删除,此方法将自动为您执行更新,并将行标记为已删除。有关用法示例,请参阅(获取数据),因为用法完全相同,只是方法名称不同。
连接表
BaseModel 还提供了连接表的方式。为此,提供了一个 join 方法,它接受 3 个输入参数。第一个是要连接的表名,第二个是连接条件数组,第三个是连接类型,默认为 INNER。要切换连接类型,Constants 类提供了 3 个常量:JOININNER(默认)、JOINLEFT 用于左连接、JOINRIGHT 用于右连接。
第一个参数是您希望与之连接的表。第二个参数是连接条件数组,必须是嵌套数组,可以选择以下选项
- leftTable - 条件中的左表,如果未设置,则使用模型表
- leftColumn - 条件中的左列,不能为空
- rightTable - 条件中的右表,如果未设置,则使用第一个传入的参数作为表名
- rightColumn - 条件中的右列,不能为空
- logicalOperator - 多个 JOIN 条件之间的逻辑运算符,如果未设置,则使用 AND
$this->join( "table2", array( array( "leftTable" => "customTable", "leftColumn" => "leftCol1", "rightTable" => "rightCustomTable", "rightColumn" => "rightCol1", ), array( "leftColumn" => "leftCol2", "rightColumn" => "rightCol2", "logicalOperator" => "OR" ) ) );
上面的示例将生成:INNER JOIN `table2` ON (`customTable`.`leftCol1` = `rightCustomTable`.`rightCol1` OR `models_table`.`leftCol2` = `table2`.`rightCol2`)。
已弃用
以下方法已弃用,应避免使用。
第一个参数是自解释的,只需传递表名。第二个参数必须是一个嵌套数组,可以包含 2 到 3 个项目。第一个项目是连接左表中的列,第二个项目是连接右表中的列。第三个参数是多个连接条件之间的链接,默认为 AND。
$this->join("table2", array(array("column1", "column1"), array("column2", "column2", "OR")));
上面的示例将生成:INNER JOIN `table2` ON (`models_table`.`column1` = `table2`.`column1` OR `models_table`.`column2` = `table2`.`column2`)。
在执行了连接查询之后,连接会被重置,如果您想再次使用它,则必须重新进行。
构建 WHERE 语句
BaseModel 提供了一个 WHERE 构建器类,您可以轻松构建自己的 WHERE 语句。
BaseModel 在其自己的属性 wBuild 中提供了此构建器,并且已经初始化,因此您可以立即使用它。要向 WHERE 语句添加表达式,Builder 类提供了一个 add 方法,它接受各种输入参数,其中两个是强制性的。
除了通过 wBuild 属性获取 WHERE 构建器外,您还可以使用 BaseModel 的 where 方法,该方法返回对象本身,因此您也可以将多个 WHERE 表达式链接在一起以及进一步链接到查询中。
已弃用 - BaseModel 提供了一些构建 WHERE 语句的变体,因此您可以构建比正常的 WHERE `column1` = 'value' AND `column2` = 'value' 更复杂的 WHERE 语句。
WHERE 表达式
要将表达式添加到 WHERE 语句中,只需使用列名和值作为输入参数调用 Builder 类的 add 方法。
$this->wBuild->add("columnName", "value");
上面的示例将生成一个简单的 WHERE 语句:`columnName` = ? 并将表达式的值放入 bind 数组中,该数组将在稍后自动绑定到您的查询。
与 where 方法类似。
$this->where("columnName1", "value")->get();
add 方法返回构建器对象,因此您可以链接方法调用,并且每次后续调用 add 方法都会在表达式之间使用 AND 逻辑运算符。
$this->wBuild->add("columnName1", "value1")->add("columnName2", 10);
上述示例将生成:`columnName1` = ? AND `columnName2` = 10,注意第二个不是 问号,因为它不需要绑定,并且安全地直接将值添加到查询中。
您还可以传递一个数组,构建器将组成一个由逗号分隔的项目列表。如果有多个项目,逗号分隔的列表被括号括起来,如果数组中有多个项目,因此这用于 IN/NOT IN 表达式。
$this->wBuild->add("columnName", array("value1", "value2"), "", "IN");
上述示例将生成:`columnName` IN (?,?),并且它将再次将值添加到 bind 数组中。您可能也注意到这个示例使用了超过 2 个输入参数,但稍后再讨论。
除了数组之外,您还可以传递一个对象,该对象将被转换为字符串,然后整个字符串被分解为一个数组,逗号用作分隔符,因此可以使用与数组相同的方式组成一个安全列表。这使得您可以使用先前查询的 Result 对象来构建 where 构建器。Result 方法 __toString 将组成所有行中第一列的列表,所以在这个例子中我们假设 $this->get(123),返回 2 行,第一列的值分别为 value1 和 value2。
$this->wBuild->add("columnName", $this->get(123), "", "NOT IN");
上述示例将生成 `columnName` IN (?,?),其中 value1 和 value2 在 bind 数组中。
要使用完全定制的 where 语句,您可以将其作为数组传递到 where 方法中,该数组包含作为第一个元素的 where 语句和作为第二个元素的绑定。
$this->where(array("columnName1 = ?", array("value1")))->get();
如果您没有绑定参数,只需将 where 语句字符串作为数组传递即可。
条件运算符
要将条件运算符更改为除默认的 AND 之外的任何运算符,只需将您想要的任何逻辑运算符作为第三个输入参数传递。
比较运算符
要将比较运算符从默认的 = 更改为其他运算符,将其传递到 add 方法作为第四个输入参数。
将列名前缀为表名
在某些情况下,特别是连接查询中,可能需要将某些列名与相应的表名一起预置,这可以通过传递表名作为第五个参数来实现。
$this->wBuild->add("columnName", "value", "", "", "tableName");
上述示例将生成:`tableName`.`columnName` = ?。
分组 WHERE 表达式
要分组 where 表达式,您需要告诉 where 构建器从哪里开始分组和在哪里结束分组,您可以通过将第六个参数设置为布尔值 true 来这样做,然后 where 构建器将在那里开始分组,当您想要结束时,传递布尔值 false 作为第六个参数,where 构建器将在该表达式之后关闭分组。
已弃用 - 条件运算符
要替换两个 WHERE 表达式之间的 AND 以其他任何条件运算符,您必须将您想要的条件运算符作为数组键中列名的前缀。
$this->getBy(array("column1" => "value1", "OR column2" => "value2"));
上述示例将生成 WHERE `column1` = 'value1' OR `column2` = 'value2'。
注意:目前这仅适用于 OR,正在努力改进。
已弃用 - 比较运算符
通常 BaseModel 在列和值之间使用 equal 比较运算符,但如果您需要任何其他运算符,您可以将它作为后缀添加到 where 数组中的列名中。
$this->getBy(array("column1 <" => 10));
上述示例将生成 WHERE `column1` < 10。
已弃用 - 分组 WHERE 表达式
您还可以按需分组表达式集。要这样做,只需在此子数组中添加一个包含进一步 where 表达式的子数组。
$this->getBy( array( array( "groupCol1" => "groupVal1", "groupCol2" => "groupVal2" ), "OR column1" => "value1" ) );
上述示例将生成 WHERE (`groupCol1` = 'groupVal1' AND `groupCol2` = 'groupVal2') OR `column1` = 'value1'。
SQL 子句
BaseModel 支持一些您可以使用 SQL 子句。
GROUP BY
要将分组子句添加到下一个查询中,使用 groupBy 方法设置它。输入参数必须是一个包含您希望按其分组的列的数组的对象,因此您可以将方法调用链接起来。
ORDER BY
要向查询中添加一个排序子句,请使用 orderBy 方法。它只会在下一个查询中使用。第一个参数必须是一个数组,且必须包含列名。第二个参数是排序方向,默认为 "升序"。该方法返回模型对象,因此您可以链接方法调用。
要在 ORDER BY 语句中使用多个排序方向,请将列名作为第一个参数的数组键,并将每个列的方向作为数组值,省略第二个参数。例如:
$this->orderBy( array( "col1" => "ASC", "col2 => "DESC" ) );
上述示例将产生 ORDER BY col1 ASC, col2 DESC。
LIMIT
要添加下一个查询的限制子句,请使用 limit 方法。它接受两个整数参数,第一个参数是要受查询影响的行数限制,第二个参数(默认为 int(0))是偏移量,表示从哪一行开始计数。
验证
BaseModel 在插入或更新时会自动验证您的数据,只要您在 rules 属性中提供验证规则即可。规则必须符合 CodeIgniter 表单验证。
$this->rules = array( array( "field" => "fieldName", "label" => "Field label", "rules" => "required|max_length[100]" ) ); $this->insert(array("fieldName" => "fieldValue"));
手动运行验证
您还可以使用 validate 方法手动运行验证。同样,您需要在 rules 属性中设置规则。
$this->rules = array( array( "field" => "fieldName", "label" => "Field label", "rules" => "required|max_length[100]" ) ); $this->validate(array("fieldName" => "fieldValue"));
跳过验证
要跳过验证,您可以将规则设置为空数组,或者在调用插入或更新方法之前调用 skipValidation 方法,这将跳过下一个查询的验证。skipValidation 会返回模型对象,因此您可以在其后链接查询。
$this->skipValidation()->insert($data);
对软删除行的查询
如果您想在软删除的行上运行更新/获取查询,请在执行查询之前调用 withDeleted 方法,或者使用自定义的 WHERE 字符串。 withDeleted 会使更新或选择查询的下一个查询仅包括已删除的行。它也返回模型对象,因此您可以链接查询。
$this->withDeleted()->get();
结果
选择查询将返回一个 Result 对象,您可以通过该对象访问数据,并遍历行。
获取列数据
要获取数据,只需访问 Result 对象的属性,并使用列名作为属性名。
$result = $this->getBy(array("whereColumn" => "whereValue"), "column"); $result->column;
如果结果是多行,则用于数据检索的是第一行。如果列不存在,则返回 null。
获取数组
要获取所有列作为数组,只需调用 asArray 方法,这将返回当前行作为数组。
$result->asArray();
行数
要获取行数,只需调用 rowCount 方法。
获取所有行
要一次性获取所有行,调用 getResult 方法。
遍历行
要遍历行,Result 类提供了 3 个方法
- next - 移动到下一行
- prev - 移动到上一行
- row - 移动到输入参数中指定的行
这三种方法都返回对象本身,或者如果下一行、上一行或指定的行不存在,则返回 false。
错误
Error 类提供了一种更简单的错误处理方式,并允许您轻松地为特定错误分配错误消息。
Error 类的初始化
为了成功分配错误消息,必须在构造时将语言数组传递给 Error 对象。BaseModel 在一些发生错误的方法中为您执行此操作,如果您需要在您自己的方法中自行执行此操作,最佳和最简单的方法是提供 CodeIgniter 语言数组 ($this->lang->language)。
添加错误
要添加一个错误,您必须提供一个错误代码,作为可选参数,您可以提供一个整数严重级别和附加错误数据数组。添加时,Error 类会根据严重性自动排序错误。此外,它会在提供的语言数组中查找相应的错误消息。消息的键必须是 "error_your_error_code",全部为小写字母。
有错误和错误计数
要检查是否存在错误,请使用 hasErrors 方法,要检查错误数量,请使用 errorCount 方法。
$error->hasErrors(); $error->errorCount();
获取错误
您可以使用 getErrors 方法一次性获取所有错误,或者使用 get 方法获取当前错误。您还可以使用 errorAt 获取特定索引处的错误,或者使用 error 方法获取包含您作为输入参数提供的代码的错误。
遍历错误
与 Result 类相同,Error 类提供了 prev 和 next 方法,如果没有前一个或下一个错误,则返回 false,或者返回自身以进行方法链接,但它不提供类似 row 的方法,除了 errorAt,它已经返回了提供的索引处的错误。
谢谢!
我要感谢所有为此项目做出贡献的人,无论是通过想法、测试、文档校对等。
变更日志
0.4.2
- 没有功能更改,新增测试和版本升级
0.4.1
- 正确处理查询中的布尔值
- 正确处理 WHERE 表达式构建器中的布尔值
0.4.0
- 自动尝试猜测表的主键列
0.3.6
- 始终在括号中包装绑定的列表,即使列表中只有一个值
- 修复 README 中的小错误
0.3.5
- 在验证之前重置表单验证
0.3.4
- 手动设置表单验证数据
0.3.3
- ORDER BY 语句中的多重排序方向
- 非 MySQL 数据库的正确 LIMIT 语法
0.3.2
- 修复无法指定特定表进行 JOIN 语句的问题
0.3.1
- 修复自定义 WHERE 字符串解析错误
0.3.0
- 添加 Error 类
- 添加验证
- 添加主键类型
- 添加 GROUP BY、ORDER BY 和 LIMIT 子句
- 添加 WHERE 语句构建器
- 添加 JOIN 语句
- 添加除 mysql(i) 以外的其他数据库驱动程序功能 - 实验!
0.2.5
- 在查询之间重置 WHERE 数组
0.2.4
- 如果没有 WHERE 语句,从查询中删除 WHERE 关键字
0.2.3
- 错误地删除了 WHERE 语句
0.2.2
- 给列名添加反引号
0.2.1
- 从绑定的占位符中删除引号
0.2.0
- 添加插入方法
- 将参数绑定到更新语句
0.1.0
- 初始版本