此包的最新版本(dev-master)没有可用的许可信息。

PHP5的轻量级几乎零配置对象关系映射器和流畅查询构建器

dev-master 2012-09-18 00:46 UTC

This package is auto-updated.

Last update: 2024-09-11 23:51:38 UTC


README

http://j4mie.github.com/idiormandparis/

PHP5的轻量级几乎零配置对象关系映射器和流畅查询构建器。

已在PHP 5.2.0+上测试 - 可能适用于更早的版本,前提是使用PDO和正确的数据库驱动程序。

BSD许可证下发布。

另请参阅:基于Idiorm构建的Active Record实现Paris

功能

  • 使简单查询和简单CRUD操作完全无痛苦。
  • 在需要更复杂的SQL时不再碍手碍脚。
  • 基于PDO构建。
  • 在整个过程中使用预编译语句以防止SQL注入攻击。
  • 不需要模型类、XML配置或代码生成:仅提供连接字符串即可开箱即用。
  • 仅包含一个名为ORM的类。全局命名空间污染最小。
  • 数据库无关。目前支持SQLite和MySQL。可能支持其他数据库,请尝试一下!

变更日志

1.0.0 - 发布于2010年12月1日

  • 初始版本

1.1.0 - 发布于2011年1月24日

  • 添加is_dirty方法
  • 添加基本查询缓存
  • 添加distinct方法
  • 添加group_by方法

1.1.1 - 发布于2011年1月30日

哲学

帕累托原理表明,大约80%的效果来自20%的原因。在软件开发中,这可以翻译成大约80%的结果来自20%的复杂性。换句话说,你可以通过相当愚蠢的方式来取得相当大的进步。

Idiorm故意的简单。其他ORM由几十个具有复杂继承层次结构的类组成,而Idiorm只有一个类,ORM,它既可以作为流畅的SELECT查询API,也可以作为简单的CRUD模型类。如果我的猜测是正确的,这应该足够许多实际应用。让我们面对现实:我们中的大多数人都不是在构建Facebook。我们正在从事小型到中型项目,其中重点是简单性和快速开发,而不是无限的灵活性和功能。

你可以将Idiorm视为一个微型ORM。它可能是“与Slim的燕尾服相配的领带”(借用DocumentCloud的一句话)。或者它可以是对那些充斥着糟糕SQL的遗留PHP应用程序进行有效清理的好方法。

Idiorm 也可能是一个构建更高级、更复杂数据库抽象的良好基础。例如,Paris 是在 Idiorm 之上实现的 Active Record 模式

让我们看看一些代码

关于 Idiorm,首先要知道的是 您不需要定义任何模型类就可以使用它。与其他几乎所有的 ORM 不同,首先要做的是设置您的模型并将它们映射到数据库表(通过配置变量、XML 文件等方式)。使用 Idiorm,您可以立即开始使用 ORM。

设置

首先,require Idiorm 源文件

require_once 'idiorm.php';

然后,将一个 数据源名称 连接字符串传递给 ORM 类的 configure 方法。这用于 PDO 连接到您的数据库。有关更多信息,请参阅 PDO 文档。ORM::configure('sqlite:./example.db');

您可能还需要通过 usernamepassword 配置选项向您的数据库驱动程序传递用户名和密码。例如,如果您正在使用 MySQL

ORM::configure('mysql:host=localhost;dbname=my_database');
ORM::configure('username', 'database_user');
ORM::configure('password', 'top_secret');

也请参阅下面的“配置”部分。

查询

Idiorm 提供了一个 流畅接口,以便在不编写任何 SQL 字符的情况下构建简单的查询。如果您使用过 jQuery,您会熟悉流畅接口的概念。这意味着您可以 连锁 方法调用,一个接一个。这可以使您的代码更易于阅读,因为按顺序连接起来的方法调用可以开始看起来像一句话。

所有 Idiorm 查询都以在 ORM 类上调用 for_table 静态方法开始。这告诉 ORM 在执行查询时使用哪个表。

请注意,此方法 不会 转义其查询参数,因此表名不应直接从用户输入传递。

然后连接方法调用以添加过滤和约束到您的查询。最后,通过调用 find_one()find_many() 结束链,执行查询并返回结果。

让我们从一个简单的例子开始。假设我们有一个名为 person 的表,该表包含以下列:id(记录的主键 - Idiorm 假设主键列名为 id,但这是可配置的,请参阅下文),nameagegender

单条记录

任何以 find_one() 结尾的方法链将返回表示您请求的数据库行的 ORM 类的 单个 实例,或者如果没有找到匹配的记录,则返回 false

要找到名称列值为 "Fred Bloggs" 的单个记录

$person = ORM::for_table('person')->where('name', 'Fred Bloggs')->find_one();

这大致对应于以下 SQL:SELECT * FROM person WHERE name = "Fred Bloggs"

要按 ID 查找单个记录,您可以直接将 ID 传递给 find_one 方法

$person = ORM::for_table('person')->find_one(5);

多条记录

任何以 find_many() 结尾的方法链将返回 ORM 类实例的 数组,每个实例对应于查询匹配的每行。如果没有找到行,则返回空数组。

要查找表中的所有记录

$people = ORM::for_table('person')->find_many();

要查找所有性别为 female 的记录

$females = ORM::for_table('person')->where('gender', 'female')->find_many();

计算结果

要返回查询将返回的行数的计数,请调用 count() 方法。

$number_of_people = ORM::for_table('person')->count();

过滤结果

Idiorm 提供了一组方法来提取满足某些条件或条件的记录。这些方法可以多次调用以构建查询,而 Idiorm 的流畅接口允许将方法调用 连锁 起来,创建易于阅读和理解查询。

注意事项

当使用Idiorm时,只能使用SQL支持的部分条件子集。此外,当查询运行时,所有的WHERE子句都会被AND操作符连接起来。目前不支持使用OR操作符连接WHERE子句。

这些限制是有意为之的:这些是迄今为止最常用的条件,通过避免对非常复杂的查询的支持,Idiorm代码库可以保持小巧和简单。

通过where_rawraw_query方法(见下文)提供对更复杂条件和支持的某些支持。如果你发现自己经常需要比Idiorm能提供的更多功能,可能考虑使用功能更全面的ORM。

等价性:wherewhere_equalwhere_not_equal

默认情况下,调用带有两个参数的where(列名和值)将使用等于运算符(=)将它们组合起来。例如,调用where('name', 'Fred')将生成子句WHERE name = "Fred"

如果你的编码风格偏好清晰而不是简洁,你可能更喜欢使用where_equal方法:这与where相同。

where_not_equal方法会在查询中添加一个WHERE column != "value"子句。

快捷方式:where_id_is

这是一个简单的辅助方法,用于通过主键查询表。尊重在配置中指定的ID列。

小于/大于:where_ltwhere_gtwhere_ltewhere_gte

有四个方法可用于不等式。

  • 小于:$people = ORM::for_table('person')->where_lt('age', 10)->find_many();
  • 大于:$people = ORM::for_table('person')->where_gt('age', 5)->find_many();
  • 小于或等于:$people = ORM::for_table('person')->where_lte('age', 10)->find_many();
  • 大于或等于:$people = ORM::for_table('person')->where_gte('age', 5)->find_many();
字符串比较:where_likewhere_not_like

要添加WHERE ... LIKE子句,使用

$people = ORM::for_table('person')->where_like('name', '%fred%')->find_many();

类似地,要添加WHERE ... NOT LIKE子句,使用

$people = ORM::for_table('person')->where_not_like('name', '%bob%')->find_many();
集合成员:where_inwhere_not_in

要添加WHERE ... IN ()WHERE ... NOT IN ()子句,分别使用where_inwhere_not_in方法。

这两个方法接受两个参数。第一个是要比较的列名。第二个是可能的值数组

$people = ORM::for_table('person')->where_in('name', array('Fred', 'Joe', 'John'))->find_many();
处理NULL值:where_nullwhere_not_null

要添加WHERE column IS NULLWHERE column IS NOT NULL子句,分别使用where_nullwhere_not_null方法。这两个方法都接受一个参数:要测试的列名。

原始WHERE子句

如果你需要一个更复杂的查询,可以使用where_raw方法来精确指定WHERE子句的SQL片段。该方法接受两个参数:要添加到查询中的字符串以及一个(可选的)数组,该数组将绑定到字符串。如果提供了参数,字符串应包含表示要绑定的值的问号字符(?),并且参数数组应包含按正确顺序替换到字符串中的值。

此方法可以在方法链中使用,与其他where_*方法以及如offsetlimitorder_by_*等方法一起使用。你提供的字符串内容将与前面的WHERE子句通过AND连接,并与后面的WHERE子句连接。

$people = ORM::for_table('person')
            ->where('name', 'Fred')
            ->where_raw('(`age` = ? OR `age` = ?)', array(20, 25))
            ->order_by_asc('name')
            ->find_many();

// Creates SQL:
SELECT * FROM `person` WHERE `name` = "Fred" AND (`age` = 20 OR `age` = 25) ORDER BY `name` ASC;

请注意,此方法仅支持“问号占位符”语法,不支持“命名占位符”语法。这是因为PDO不允许包含不同类型占位符的查询。此外,您应确保字符串中的问号占位符数量与数组中的元素数量完全匹配。

如果您需要更多的灵活性,您可以手动指定整个查询。请参阅下方的原始查询

限制和偏移量

请注意,这些方法不会转义它们的查询参数,因此这些不应该直接从用户输入传递。

limitoffset方法与它们的SQL等价物非常接近。

$people = ORM::for_table('person')->where('gender', 'female')->limit(5)->offset(10)->find_many();
排序

请注意,此方法不会转义其查询参数,因此不应该直接从用户输入传递。

提供了两种方法来添加查询中的ORDER BY子句。这些是order_by_descorder_by_asc,每个都接受一个列名来排序。

$people = ORM::for_table('person')->order_by_asc('gender')->order_by_desc('name')->find_many();

分组

请注意,此方法不会转义其查询参数,因此不应该直接从用户输入传递。

要向查询中添加GROUP BY子句,请调用group_by方法,传入列名。您可以多次调用此方法以添加更多列。

$poeple = ORM::for_table('person')->where('gender', 'female')->group_by('name')->find_many();

结果列

默认情况下,您的查询将返回SELECT语句中的所有列。也就是说,调用

$people = ORM::for_table('person')->find_many();

将产生以下查询

SELECT * FROM `person`;

select方法让您控制哪些列被返回。多次调用select来指定要返回的列。

$people = ORM::for_table('person')->select('name')->select('age')->find_many();

将产生以下查询

SELECT `name`, `age` FROM `person`;

可选地,您还可以向select提供一个第二个参数,以指定列的别名

$people = ORM::for_table('person')->select('name', 'person_name')->find_many();

将产生以下查询

SELECT `name` AS `person_name` FROM `person`;

传递给select的列名将被自动引号引用,即使它们包含table.column风格的标识符也是如此

$people = ORM::for_table('person')->select('person.name', 'person_name')->find_many();

将产生以下查询

SELECT `person`.`name` AS `person_name` FROM `person`;

如果您想覆盖此行为(例如,提供数据库表达式),您应改用select_expr方法。同样,它也接受别名作为可选的第二个参数。

// NOTE: For illustrative purposes only. To perform a count query, use the count() method.
$people_count = ORM::for_table('person')->select('COUNT(*)', 'count')->find_many();

将产生以下查询

SELECT COUNT(*) AS `count` FROM `person`;

DISTINCT

要在查询的结果列列表之前添加DISTINCT关键字,请向查询链添加对distinct()的调用。

$distinct_names = ORM::for_table('person')->distinct()->select('name')->find_many();

这将产生以下查询

SELECT DISTINCT `name` FROM `person`;

连接

Idiorm提供了一系列方法来为构建的查询添加不同类型的JOIN

方法:joininner_joinleft_outer_joinright_outer_joinfull_outer_join

这些方法都接受相同的参数集。以下描述将使用基本的join方法作为示例,但同样适用于每个方法。

前两个参数是必须的。第一个是要连接的表名,第二个提供了连接的条件。建议以一个包含三个组件的数组指定条件:第一个列,运算符和第二个列。表和列名将被自动引号引用。例如

$results = ORM::for_table('person')->join('person_profile', array('person.id', '=', 'person_profile.person_id'))->find_many();

也可以指定条件为字符串,它将按原样插入到查询中。然而,在这种情况下,列名将不会被转义,因此应谨慎使用此方法。

// Not recommended because the join condition will not be escaped.
$results = ORM::for_table('person')->join('person_profile', 'person.id = person_profile.person_id')->find_many();

join方法还接受一个可选的第三个参数,它是查询中的表的别名。如果您想将表连接到它自己以创建层次结构,这很有用。在这种情况下,最好将其与table_alias方法结合使用,它将为与ORM关联的表添加别名,并使用select方法来控制哪些列被返回。

$results = ORM::for_table('person')
    ->table_alias('p1')
    ->select('p1.*')
    ->select('p2.name', 'parent_name')
    ->join('person', array('p1.parent', '=', 'p2.id'), 'p2')
    ->find_many();

原始查询

如果您需要执行更复杂的查询,您可以使用raw_query方法完全指定要执行的查询。此方法接受一个字符串和一个参数数组。字符串应包含占位符,无论是问号还是命名占位符语法,这些占位符将用于将参数绑定到查询。

$people = ORM::for_table('person')->raw_query('SELECT p.* FROM person p JOIN role r ON p.role_id = r.id WHERE r.name = :role', array('role' => 'janitor')->find_many();

ORM类实例返回将包含查询返回的所有列的数据。请注意,即使您可以在查询中指定一个完全不同的表,您仍然必须调用for_table来将实例绑定到特定的表。这是因为如果您稍后需要调用save,ORM将需要知道要更新哪个表。

请注意,使用raw_query是高级的,也可能很危险,Idiorm不会尝试在您使用此方法时保护您免犯错误。如果您经常调用raw_query,您可能没有正确理解使用ORM的目的,或者您的应用程序可能过于复杂,不适合Idiorm。考虑使用功能更齐全的数据库抽象系统。

从对象获取数据

一旦从查询中获取到一组记录(对象),您可以通过两种方式访问这些对象上的属性(存储在其对应表中的列的值):使用get方法,或者直接访问对象上的属性。

$person = ORM::for_table('person')->find_one(5);

// The following two forms are equivalent
$name = $person->get('name');
$name = $person->name;

您还可以使用as_array方法获取ORM实例包裹的所有数据。这将返回一个关联数组,将列名(键)映射到它们的值。

as_array方法接受列名作为可选参数。如果提供了这些参数中的一个或多个,则只返回匹配的列名。

$person = ORM::for_table('person')->create();

$person->first_name = 'Fred';
$person->surname = 'Bloggs';
$person->age = 50;

// Returns array('first_name' => 'Fred', 'surname' => 'Bloggs', 'age' => 50)
$data = $person->as_array();

// Returns array('first_name' => 'Fred', 'age' => 50)
$data = $person->as_array('first_name', 'age');

更新记录

要更新数据库,更改对象的一个或多个属性,然后调用save方法将更改提交到数据库。同样,您可以更改对象的属性值,要么使用set方法,要么直接设置属性的值。

$person = ORM::for_table('person')->find_one(5);

// The following two forms are equivalent
$person->set('name', 'Bob Smith');
$person->age = 20;

// Syncronise the object with the database
$person->save();

创建新记录

要添加新记录,您首先需要创建一个“空”对象实例。然后,像往常一样设置对象的值,并保存它。

$person = ORM::for_table('person')->create();

$person->name = 'Joe Bloggs';
$person->age = 40;

$person->save();

对象保存后,您可以调用其id()方法来找到数据库为其自动生成的自增主键值。

检查属性是否已修改

要检查属性自对象创建(或上次保存)以来是否已更改,请调用is_dirty方法。

$name_has_changed = $person->is_dirty('name'); // Returns true or false

删除记录

要从数据库中删除对象,只需调用其delete方法。

$person = ORM::for_table('person')->find_one(5);
$person->delete();

事务

Idiorm不提供任何额外的方法来处理事务,但使用PDO的内置方法非常容易。

// Start a transaction
ORM::get_db()->beginTransaction();

// Commit a transaction
ORM::get_db()->commit();

// Roll back a transaction
ORM::get_db()->rollBack();

有关详细信息,请参阅PDO事务文档

配置

除了设置数据库连接的DSN字符串(见上文)外,configure方法还可以用于设置ORM类的一些其他简单选项。修改设置涉及传递一个键/值对给configure方法,表示您希望修改的设置和要设置的值。

ORM::configure('setting_name', 'value_for_setting');

数据库认证详情

设置:usernamepassword

某些数据库适配器(如MySQL)需要为DSN字符串单独提供用户名和密码。这些设置允许您提供这些值。一个典型的MySQL连接设置可能如下所示:

ORM::configure('mysql:host=localhost;dbname=my_database');
ORM::configure('username', 'database_user');
ORM::configure('password', 'top_secret');

PDO驱动程序选项

设置:driver_options

某些数据库适配器需要(或允许)传递一个包含特定驱动程序配置选项的数组。此设置允许您将这些选项传递给PDO构造函数。有关更多信息,请参阅PDO文档。例如,要强制MySQL驱动程序使用UTF-8进行连接:

ORM::configure('driver_options', array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));

PDO错误模式

设置:error_mode

这可以用于设置Idiorm使用的数据库连接类上的PDO::ATTR_ERRMODE设置。它应传递PDO定义的类常量之一。例如:

ORM::configure('error_mode', PDO::ERRMODE_WARNING);

默认设置是 PDO::ERRMODE_EXCEPTION。有关可用的错误模式的完整详细信息,请参阅 PDO 文档

标识符引号字符

设置: identifier_quote_character

设置用于引号标识符的字符(例如表名、列名)。如果没有设置,PDO 会根据所使用的数据库驱动程序自动检测。

ID 列

默认情况下,ORM 假设您所有表都有一个名为 id 的主键列。有两种方法可以覆盖此设置:对数据库中的所有表或对每个表分别设置。

设置: id_column

此设置用于配置所有表的主键列名称。如果您的 ID 列名为 primary_key,则使用

ORM::configure('id_column', 'primary_key');

设置: id_column_overrides

此设置用于分别指定每个表的主键列名称。它接受一个关联数组,将表名映射到列名。例如,如果您的 ID 列名称包含表名,则可以使用以下配置

ORM::configure('id_column_overrides', array(
    'person' => 'person_id',
    'role' => 'role_id',
));

查询日志

设置: logging

Idiorm 可以记录它执行的所有查询。要启用查询日志,将 logging 选项设置为 true(默认为 false)。

当查询日志启用时,您可以使用两个静态方法来访问日志。 ORM::get_last_query() 返回最近执行的查询。 ORM::get_query_log() 返回所有已执行查询的数组。

查询缓存

设置: caching

Idiorm 可以在请求期间缓存它执行的查询。要启用查询缓存,将 caching 选项设置为 true(默认为 false)。

当查询缓存启用时,Idiorm 将缓存它执行的每个 SELECT 查询的结果。如果 Idiorm 遇到已运行的查询,它将直接从其缓存中获取结果,而不是执行数据库查询。

警告和注意事项
  • 请注意,这是一个内存缓存,仅在单个请求期间保留数据。这不是持久缓存(如 Memcached)的替代品。

  • Idiorm 的缓存非常简单,不会在数据更改时尝试使自身失效。这意味着如果您运行查询检索一些数据,修改并保存它,然后再次运行相同的查询,结果将是过时的(即,它们不会反映您的更改)。这可能会在您的应用程序中引起微妙的错误。如果您启用了缓存并且遇到奇怪的行为,请禁用它并再次尝试。如果您需要进行此类操作但仍希望使用缓存,可以调用 ORM::clear_cache() 来清除所有现有缓存查询。

  • 启用缓存会增加您应用程序的内存使用量,因为每个请求期间获取的所有数据库行都保留在内存中。如果您处理大量数据,您可能希望禁用缓存。