figdice/gazedb

简单PDO包装器,用于敏捷且安全的ORM和直接查询

3.0 2018-10-25 06:52 UTC

This package is not auto-updated.

Last update: 2024-09-28 18:35:49 UTC


README

简单PDO包装器,用于PHP的敏捷且安全的ORM和直接SQL查询

1. 摘要

当不需要完整的ORM框架时,请使用此库。

gazedb 不提供 的功能

  • 全面映射完整数据库模式
  • 缓存层
  • 声明式关系语法
  • 集合的懒加载

如果您不知道如何编写干净的、高效的SQL查询,或者如果您不了解索引如何帮助您的架构,或者如果您计划每周末更换底层数据库管理系统供应商,您应该使用其他库(如Doctrine)。您可能需要学习新的查询语言(Hibernate QL、Doctrine QL等)以及框架特定的基于注释的复杂语法来声明表之间的关系。

gazedb 提供 的功能

  • 简单的 PDO 包装器
  • 基于规范性常量的表和列名称的表示法
  • 简单的单对象CRUD操作辅助函数
  • 简单的语法,以可重用的方式帮助您创建自己的真实SQL查询

在大多数情况下,您的gazedb模型对象不知道它们之间如何关联。数据库的智能仍然掌握在您的手中(索引、最佳连接方式、何时以及如何检索等)。

2. 模型对象

为每个表创建一个类,作为ModelObject的子类。

class Employee extends ModelObject

子类 必须 实现以下方法

  • tableName
  • mapFields

ModelObject子类 可能 实现以下方法

  • mapPK
  • mapAutoIncrement

2.1. 表名称

/**
 * Must override. Returns the name of the table.
 * @return string
 */
protected static function tableName()
{
  return 'employees';
}

您永远不会直接使用tableName()。此方法用于祖先的table()静态方法。

Employee::table()返回为Employee类配置的数据库表名称。

用法

$query = "select * from ".Employee::table()." limit 10"

2.2. 列

为您的表字段声明类常量。

class Employee extends ModelObject
{
  public const ID = 'employee_id';
  public const LASTNAME = 'lastname';
  public const SALARY = 'salary';
  public const DEPARTMENT = 'dept_id';

这些const不是由库显式使用的;相反,它们是可重用性辅助工具,以便您可以在代码和查询中编写非硬编码的DB标识符。

您必须通过mapFields方法告诉gazedb哪些列是数据交换的一部分

/**
 * Must override. Returns the associative array of the columns mapping
 * (column name => default value)
 * @return array
 */
public static function mapFields()
{
  return [
    self::ID => null,
    self::LASTNAME => '',
    self::SALARY => 0,
    self::DEPARTMENT => null
  ];
}

并且您必须编写列的mutators

public function getLastname() { return $this->column(self::LASTNAME); }

/**
 * @return Employee
 */
public function setLastname($value) { return $this->assign(self::LASTNAME, $value); }

通过提示返回类型为同一类来使您的设置器链式化

2.3. 主键

您可以通过覆盖方法来指定主键(包括多列主键)

    /**
     * Should override, if the table has a PK (single- or multiple-field).
     * Returns an array of field names.
     * @return array
     */
    public function mapPK()

您永远不需要显式调用此方法。一个典型的mapPK实现示例是

  public function mapPK()
  {
    return [ self::ID ];
  }

2.4. 自增

如果您的表有一个数据库在插入时自动分配的自增列,则提供mapAutoIncrement的实现。

/**
 * The name of the auto-increment column.
 * @return string
 */
public function mapAutoIncrement() {
    return self::ID;
}

3. 构建您的查询

您通过利用const名称的优势,在代码中编写典型查询。

$query = "
  select
    Employee.".Employee::ID.",
    Employee.".Employee::LASTNAME.",
    Dept.".Department::FLOOR."
  from
    ".Employee::table()." Employee
    inner join ".Department::table()." Dept
      on Dept.".Department::ID." = Employee.".Employee::DEPARTMENT."
  where
    Employee.".Employee::SALARY." > 10000
";

因此,您以您选择的目标SQL方言(即实际的SQL引擎的特定语法和函数)编写真实、有效的SQL。

您可以使用PDO附带的标准参数绑定(:param语法),并应小心处理SQL注入保护。

使用上述建议编写查询所能获得的唯一好处,是确保表和字段名称的一致性和语法检查。

4. 数据库对象

gazedb 允许您同时连接到多个不同的数据源。它使用可注入的单例模式,具有命名实例。

$db = Database::get();
$archiveDB = Database::get('archive');

您必须在数据库实例上调用 injectDsn($dsnString, $username, $password) 来指定 PDO 连接字符串。

然后,您可以直接使用以下方法操作底层的 PDO 实例:

$db->pdo()

该方法返回您的普通且熟悉的 PDO 对象,供您执行

$recordset = $db->pdo()->query($query);

4.1. CRUD 操作

除了直接在 $database->pdo() 实例上执行底层的 PDO 操作外,gazedb 还为那些映射主键的模型对象提供了简单的 CRUD 自动映射方法。

4.1.1. 加载

// "new" does not create anything in DB
$employee = new Employee();

// Specify the key value for the employee you wish to load:
$employee->setId(12);

// Fetch the record and auto-set all the mapped columns (see mapFields() method)
$database->load($employee);

echo $employee->getLastname();

如果指定主键的记录找不到,Database::load 方法将抛出 ObjectNotFoundException 异常。

4.1.2. 更新

一旦您有一个已填充的对象,您可以使用其 mutators 修改任何字段,并使用 update 方法将其保存回数据库。

$employee->setFloor(8);
$database->update($employee);

update 方法产生一个查询,仅更改您明确修改的值,其他所有字段保持不变。

注意:gazedb 在将对象存储回数据库之前不会检查对象的状态。如果记录被另一个进程或连接更改,您的 udpate 语句仍将被执行,而您可能并不知道。

同样,update 不会在数据库中更改自您上次调用 load 以来更改的字段重新获取对象字段。

4.1.3. 插入

$employee = new Employee();
$employee
  ->setLastname('Smith')
  ->setFloor(10)
  ->setSalary(60000);

$database->insert($employee);

echo $employee->getId();

insert 方法会触发一个插入查询,如果您的模型对象中指定了自增字段,则可选地将自增值分配给映射的自增字段。

insert 调用后,您的对象被认为是“干净的”,您可以在仅对修改的值执行 update 操作之前,通过 mutators 再次修改其值。