byjoby/destructr

一个用于在关系型数据库中存储结构化和非结构化数据的库

v1.7.0 2022-06-08 17:11 UTC

README

PHPUnit Tests

Destructr 是一种专业的对象关系映射(ORM)工具,它允许无缝地将结构化、关系型数据与非结构化的 JSON 数据混合。

入门指南

Destructr 的目的是允许许多“类型”的对象存储在单个表中。每个 Destructr 数据对象(DSO)只包含一个数组,该数组将被保存到数据库中作为 JSON。数组访问也被简化,使用点作为分隔符,因此您可以通过 $dso["foo.bar"] 来访问数据,而不是通过 $dso["foo"]["bar"]。这是出于两个原因。它避免了通过引用更新嵌套数组值的问题,并且为使用字符串定位非结构化数据节点提供了一个明确的方式,这与我们可以编写 SQL 查询来引用它们的方式类似。

如果这个想法听起来非常慢,那是因为它确实很慢。幸运的是,MySQL 和 MariaDB 提供了我们可以利用的机制,可以从任何部分的非结构化数据生成生成列,这样就可以将其中的一部分提取到它们自己的虚拟列中用于索引和更快的搜索/排序。

数据库驱动器和工厂

为了从数据库表中读取/写入对象,您需要配置一个驱动器(Driver)和工厂(Factory)类。

// DriverFactory::factory() has the same arguments as PDO::__construct
// You can also construct a driver directly, from a class in Drivers,
// but for common databases DriverFactory::factory should pick the right class
$driver = \Destructr\DriverFactory::factory(
  'mysql:host=127.0.0.1',
  'username',
  'password'
);
// Driver is then used to construct a Factory
$factory = new \Destructr\Factory(
  $driver,      //driver is used to manage connection and generate queries
  'dso_objects' //all of a Factory's data is stored in a single table
);

创建新记录

接下来,您可以使用工厂创建一个新的记录对象。

// by default all objects are the DSO class, but factories can be made to use
// other classes depending on what data objects are instantiated with
$obj = $factory->create();

// returns boolean indicating whether insertion succeeded
// insert() must be called before update() will work
$obj->insert();

// set a new value and call update() to save changes into database. update()
// will return true without doing anything if no changes have been made.
$obj['foo.bar'] = 'some value';
$obj->update();

// deleting an object will by default just set dso.deleted to the current time
// objects with a non-null dso.deleted are excluded from queries by default
// delete() calls update() inside it, so its effect is immediate
$obj->delete();

// objects that were deleted via default delete() are recoverable via undelete()
// undelete() also calls update() for you
$obj->undelete();

// objects can be actually removed from the table by calling delete(true)
$obj->delete(true);

搜索

工厂提供了一个创建 Search 对象的接口,允许您以结构化和抽象的方式输入各种 SQL 子句。

// get a new search object from the factory
$search = $factory->search();

// Search::where() takes SQL for the WHERE clause of a query
// ${path} syntax is used to reference data within objects, and
// works everywhere in searches
$search->where('${dso.date.modified} > :time');

// Search::order() takes SQL to go inside an ORDER BY clause
// in the final query.
$search->order('${dso.date.modified} desc');

// Search limit/offset methods can be used for pagination
// there is also a paginate() method for more conveniently
// paginating results
$search->paginate(20,1);

// Search::execute() returns an array of the resulting objects
$results = $search->execute();

要求

此系统高度依赖于底层数据库的 JSON 功能。这意味着它不可能在没有支持 JSON 功能的数据库上运行。基本上,如果一个数据库没有 JSON 函数,那么 Destructr 可能永远无法与之配合使用。

目前,对以下数据库有相当不错的支持:

  • MySQL >=5.7.8
  • MariaDB >=10.2.7
  • SQLite 3(存在一些限制)

在实践中,这意味着 Destructr 永远无法在以下版本的流行数据库上运行:

  • MySQL >=5.7.8
  • MariaDB >=10.2.7
  • PostgreSQL >=9.3
  • SQL Server >=2016

从理论上讲,Destructr 也非常适合 NoSQL 数据库。如果我有需要,它很可能能够为类似 MongoDB 这样的数据库编写驱动器。它甚至可能相当容易。

SQLite 注意事项

MySQL 和 MariaDB 驱动器使用它们的本地 JSON 函数自动生成虚拟列。SQLite(在大多数环境中)没有本地 JSON,因此 Destructr 本身会在插入或更新对象时手动更新虚拟列。在实践中,如果您通过 Destructr 进行所有插入和更新,这不会产生影响。但是,如果您通过任何其他方法更新数据库,则需要注意这一点,并手动更新虚拟列的值。