graze / dal
数据访问层
Requires
- php: >=5.5.0
- doctrine/common: ^2.5
- doctrine/inflector: ^1.1
- graze/standards: dev-master
- ocramius/generated-hydrator: ^1.2
- ocramius/proxy-manager: ^1.0
- symfony/console: ^2.8
- zendframework/zend-code: ^2.6
- zendframework/zend-hydrator: ^1.0
Requires (Dev)
- adlawson/timezone: ~1.0
- aura/sql: ^2.4
- doctrine/orm: ^2.5
- guzzlehttp/guzzle: ^6.1
- illuminate/database: ^5.2
- mockery/mockery: ^0.9.4
- phpunit/phpunit: ~4.0
- squizlabs/php_codesniffer: ^2.7,<2.8.1
- symfony/var-dumper: ^2.6
- symfony/yaml: ^2.8
Suggests
- aura/sql: Required when using the PdoAdapter
- doctrine/orm: Required when using the DoctrineOrmAdapter
- guzzlehttp/guzzle: Required when using the RestAdapter
- illuminate/database: Required when using the EloquentOrmAdapter
- symfony/yaml: Required when using factory methods on adapters
This package is auto-updated.
Last update: 2024-08-28 01:18:01 UTC
README
DAL 是一个 PHP 数据访问层,旨在在您的应用程序和持久层之间添加一个额外的抽象层。这个库的主要目标是允许使用多个持久层,每个持久层可能采用不同的抽象模式,但都通过一个 单一 接口使用。
数据映射模式 在将数据持久化的细节隐藏在其接口后面方面非常出色。DAL 通过包含多个持久层并支持除数据映射以外的其他模式(例如 活动记录)来改进这种抽象。
我们正在内部使用它来将我们的应用程序转向一个更可管理的数据映射层,而不是我们当前的 active record 实现。这将是我们在可预见的未来跨 PHP 应用程序访问持久层的接口。我们将继续在 DAL 下方使用我们的 active record 实现,直到我们决定完全移除它,那时 DAL 将保持原位。
DAL 的主要接口模仿 Doctrine ORM 的 API,具有类似命名的 getRepository()
、persist()
和 flush()
方法。通过 getRepository()
方法公开的仓库甚至实现了 Doctrine 的 ObjectRepository
,所有这些都旨在与 PHP 中功能最完整的数据映射库之一具有共同基础。
您可以根据自己的喜好以任何方式进行安装,但我们推荐 Composer。
{ "require": { "graze/dal": "^1.0" } }
$ composer require graze/dal
文档
开始使用 Eloquent
使用 Eloquent 与 DAL 需要安装 illuminate/eloquent
包。如果您在 Laravel 之外使用 Eloquent,以下资源可能会有所帮助: 如何在 Laravel 之外使用 Eloquent, 在 Laravel 之外使用 Eloquent。
配置 DalManager
use Graze\Dal\Adapter\Orm\EloquentOrmAdapter; $eloquentAdapter = EloquentOrmAdapter::createFromYaml(/*Eloquent DB Connection*/, ['path/to/config/eloquent.yml']); $dal = new DalManager([$eloquentAdapter]);
在我们的应用程序中设置了一个 DalManager
对象,现在我们需要为我们的实体编写一些配置
编写配置
适配器提供两种配置方法 createFromYaml
和 createFromArray
,在本文档中所有示例都使用 YAML,但您也可以使用数组或任何可以转换为数组的任何内容。
App\Entity\Product: record: App\Eloquent\Product adapter: Graze\Dal\Adapter\Orm\EloquentOrmAdapter repository: App\Repository\ProductRepository table: products fields: id: mapsTo: id type: int name: mapsTo: name type: string
这是我们在应用程序中基本 Product
实体的配置。它配置了以下字段
record
- 这是您持久层提供的类,在这种情况下是一个 Eloquent 模型。adapter
- 这是管理此实体的适配器。repository
(可选)- 这是此实体的自定义仓库类,如果在此处未指定,DAL 提供了一个通用仓库。table
- 这是特定于适配器的字段,在这种情况下,我们需要为我们提供 Eloquent 模型此实体的表名。fields
- 定义实体的每个字段,mapsTo
字段指的是我们将用于此字段的底层 Eloquent 模型的属性。
生成类
使用此配置,我们实际上不需要为我们的实体编写任何PHP代码,DAL可以为我们生成所有代码。通过运行此命令,DAL将生成一个实体类、一个存储库以及我们开始所需的底层Eloquent模型。
$ bin/dal generate path/to/config/eloquent.yml App src
使用DalManager
我们现在已经拥有了开始使用我们的实体所需的所有内容,操作方式如下
$product = $dalManager->getRepository('App\Entity\Product')->find(1); echo $product->getName();
开始使用 Doctrine
开始使用Doctrine与开始使用Eloquent非常相似。关键区别在于DAL目前不支持为您生成底层的Doctrine类和配置,因此您需要自己编写这些代码。您还需要doctrine/orm
包。
配置 DalManager
use Graze\Dal\Adapter\Orm\DoctrineOrmAdapter; use Doctrine\ORM\EntityManager; $em = new EntityManager(); // see Doctrine's documentation for setting this up $doctrineAdapter = DoctrineOrmAdapter::createFromYaml($em, ['path/to/config/doctrine.yml']); $dal = new DalManager([$doctrineAdapter]);
编写配置
App\Entity\Product: record: App\Doctrine\Product repository: App\Repository\ProductRepository fields: id: mapsTo: id type: int name: mapsTo: name type: string
您还需要编写底层Doctrine实体的Doctrine配置。
生成DAL实体和存储库
$ bin/dal generate path/to/config/doctrine.yml App src
注意:当前不支持生成Doctrine实体。您必须自己编写这些代码。
使用DalManager
$product = $dalManager->getRepository('App\Entity\Product')->find(1); echo $product->getName();
开始使用 PDO
DAL还提供了一个非常简单的PdoAdapter
,如果您不需要ORM提供的特性,但仍然想要一组合理的数据管理接口,那么您可以使用它。不过,这依赖于aura/sql
包,所以请确保您已将其配置为应用的依赖项。
配置 DalManager
use Graze\Dal\Adapter\Pdo\PdoAdapter; use Aura\Sql\ExtendedPdo; $pdo = new ExtendedPdo(); // @see https://github.com/auraphp/Aura.Sql#lazy-connection-instance for setting this up $pdoAdapter = PdoAdapter::createFromYaml($pdo, ['path/to/config/pdo.yml']); $dal = new DalManager([$pdoAdapter]);
编写配置
App\Entity\Product: table: products repository: App\Repository\ProductRepository fields: id: mapsTo: id type: int name: mapsTo: name type: string
注意,这里没有record
字段,因为没有底层的模型或记录类与PDO相关联,这是不必要的。
生成DAL实体和存储库
没有记录/模型需要生成,所以我们只需要通过运行以下命令来生成DAL实体和存储库
$ bin/dal generate path/to/config/pdo.yml App src
使用DalManager
$product = $dalManager->getRepository('App\Entity\Product')->find(1); echo $product->getName();
关系
实体之间的关系应在DAL级别定义,而不是在底层持久化层中定义。这是为了方便不同适配器管理实体。
App\Entity\Customer: record: App\Eloquent\Customer repository: App\Repository\CustomerRepository table: customers fields: id: mapsTo: id type: int firstName: mapsTo: first_name type: string lastName: mapsTo: last_name type: string related: orders: type: oneToMany entity: App\Entity\Order foreignKey: customer_id collection: true App\Entity\Order: record: App\Eloquent\Order table: orders fields: id: mapsTo: id type: int price: mapsTo: price type: float related: customer: type: manyToOne entity: App\Entity\Customer localKey: customer_id
此示例显示了客户和订单之间的简单关系。客户拥有许多订单,因此与订单实体有一个oneToMany
类型,使用订单表上的customer_id
字段作为外键,并表明这将是一个实体集合。
在订单实体配置中,我们定义了一个单独的客户字段,类型为manyToOne
,因为订单属于客户,因此使用订单表上的customer_id
字段作为本地键来确定哪个客户拥有此订单。
localKey
和foreignKey
指的是数据库表上的字段,而不是DAL实体或底层持久化层实体。因此,当前仅在关系的一侧至少有一个使用SQL作为其底层存储机制实体的情况下,才支持关系。
上面的示例显示了manyToOne
和oneToMany
关系类型,还有manyToMany
。
多对多关系
多对多关系需要两个实体和一个存储它们之间关系的枢纽表
App\Entity\Order: record: App\Eloquent\Order table: orders fields: id: mapsTo: id type: int price: mapsTo: price type: float related: customer: type: manyToOne entity: App\Entity\Customer localKey: customer_id products: type: manyToMany entity: App\Entity\Product pivot: order_item localKey: order_id foreignKey: product_id collection: true
在这里,我们扩展了订单实体,使其与许多产品相关联,当然,单个产品也可以属于许多订单。
与其他关系一样,我们定义了type
和entity
,然后需要定义枢纽表以及两个键,localKey
和foreignKey
,这些键位于枢纽表上。其中,localKey
是存储为此配置的实体ID的字段,在本例中为订单,而foreignKey
是存储与我们相关联的实体ID的字段,在本例中为产品。
$ bin/dal generate path/to/config/eloquent.yml App src
$customer = $dalManager->getRepository('App\Entity\Customer')->findBy(['email' => 'customer@example.com']); $orders = $customer->getOrders(); foreach ($orders as $order) { echo $order->getPrice(); }
使用多个适配器
use Graze\Dal\Adapter\Pdo\PdoAdapter; use Graze\Dal\Adapter\Orm\EloquentOrmAdapter; use Aura\Sql\ExtendedPdo; $pdoAdapter = PdoAdapter::createFromYaml(new ExtendedPdo(/*see Aura docs*/), ['path/to/config/pdo.yml']); $eloquentAdapter = EloquentOrmAdapter::createFromYaml(/* see eloquent docs */, ['path/to/config/eloquent.yml']); $dalManager = new DalManager([$pdoAdapter, $eloquentAdapter]);
现在,我们已经设置了一个带有两个配置适配器的DalManager,我们可以编写配置来设置两个不同适配器的实体,并在它们之间创建关系
# eloquent.yml App\Entity\Customer: record: App\Eloquent\Customer repository: App\Repository\CustomerRepository table: customers fields: id: mapsTo: id type: int firstName: mapsTo: first_name type: string lastName: mapsTo: last_name type: string related: orders: type: oneToMany entity: App\Entity\Order foreignKey: customer_id collection: true # pdo.yml App\Entity\Order: table: orders fields: id: mapsTo: id type: int price: mapsTo: price type: float related: customer: type: manyToOne entity: App\Entity\Customer localKey: customer_id
现在我们可以生成所需的全部实体、存储库和记录
$ bin/dal generate path/to/config/eloquent.yml App src
就像在所有之前的示例中使用的那样
$customer = $dalManager->getRepository('App\Entity\Customer')->findBy(['email' => 'customer@example.com']); $orders = $customer->getOrders(); foreach ($orders as $order) { echo $order->getPrice(); }
这使我们能够通过不同的适配器和存储机制处理不同的数据,但通过单个接口创建它们之间的关系。每个实体在幕后如何管理都被抽象化,从我们的高级代码中分离出来。
这开辟了以下可能性:
use Graze\Dal\Adapter\Orm\EloquentOrmAdapter; use App\Dal\Adapter\HttpAdapter; $httpAdapter = HttpAdapter::createFromYaml(new GuzzleHttp\Client(), ['path/to/config/http.yml']); $eloquentAdapter = EloquentOrmAdapter::createFromYaml(/* see eloquent docs */, ['path/to/config/eloquent.yml']); $dalManager = new DalManager([$httpAdapter, $eloquentAdapter]);
数据库支持
理论上,DAL支持底层持久层(如Doctrine、Eloquent等)所支持的所有数据库。然而,DAL仅官方支持MySQL。这是因为处理关系类型的代码目前依赖于DAL中编写的SQL查询,这些查询仅在MySQL上进行过测试。
如果你正在使用持久层支持的数据库,不妨试试,在90%的情况下它可能表现得很出色。我们将在未来努力正式支持其他数据库。
贡献 & 支持
如果你有支持疑问,请创建一个issue并标记为“support”。如果你想贡献,请先创建一个PR或issue进行讨论。文档贡献非常受欢迎。
开发
有一个docker-compose文件,你可以使用它来启动开发和测试环境。
$ make install
$ make test
许可证
本库的内容由 Nature Delivered Ltd 根据 MIT许可证 发布。
你可以在 LICENSE
或 https://open-source.org.cn/licenses/mit 找到此许可证的副本。