efabrica / nette-repository
Nette 数据库的仓库
Requires
- php: ^8.1
- ext-json: *
- ext-pdo: *
- doctrine/inflector: ^2.0
- nette/caching: ^3.1
- nette/database: ^3.1 <3.2
- nette/di: ^3.1
- nette/php-generator: ^4.1.4
- nikic/php-parser: ^4.16|^5.0
- symfony/console: ^5.4|^6.0|^7.0
- symfony/polyfill-php80: ^1.29
Requires (Dev)
- nesbot/carbon: ^3.1
- nette/application: ^3.1
- nette/bootstrap: ^3.1
- nette/http: ^3.2
- phpunit/phpunit: ^9.6
- ramsey/uuid: ^4.2
- tracy/tracy: ^2.9
This package is auto-updated.
Last update: 2024-09-22 09:23:46 UTC
README
此扩展通过提供类型提示实体(ActiveRows)、查询(Selections)和仓库(服务)来增强您 Nette 数据库的静态分析。
安装
您可以使用 Composer(PHP 的依赖管理器)安装此扩展。
composer require efabrica/nette-repository
要启用扩展,您需要将其注册到配置中
extensions: netteRepo: Efabrica\NetteRepository\Bridge\EfabricaNetteRepositoryExtension
最后,您可以运行仓库代码生成命令以生成必要的类和文件
$ php vendor/bin/enc
用法
实体
Entity
类是 ActiveRow 的子类,作为您实体的超类。您可以使用我们的代码生成工具自动创建它,或者手动编写。
插入实体
assert($repository instanceof PersonRepository); assert($entity instanceof Person); $entity = $repository->create(); $entity->name = 'John'; $entity->surname = 'Doe'; $entity->age = 42; $entity->save();
保存数组
$entity = $repository->insertOne([ Person::NAME => 'John', Person::SURNAME => 'Doe', Person::AGE => 42, ]); // always returns entity // More verbose approach: $entity = $repository->create(); $entity->fill([ Person::NAME => 'John', Person::SURNAME => 'Doe', Person::AGE => 42, ]); $entity->save();
经典
$person = $repository->insert([ Person::NAME => 'John', Person::SURNAME => 'Doe', Person::AGE => 42, ]); // always returns Entity
多插入
$persons = []; foreach (range(30, 40) as $age) { $person = $repository->createRow(); Person::NAME => 'John', Person::SURNAME => 'Doe', Person::AGE => $age, $persons[] = $person; } $repository->insertMany($persons); // always returns int
更新实体
$entity = $repository->find($id); $entity->name = 'Jake'; $entity->update(); // or $entity->save();
经典
$repository->update($id, [Person::name => 'Jake']);
删除实体
$repository->delete($id);
或者,如果您已经有了实体
$entity = $repository->find($id); $entity->delete();
作用域
作用域是一个定义了为 Repository、Query 和 Entity 禁用哪些现有行为的类。
活动作用域从 Repository 传递到 Query,再从 Query 传递到 Entity。
->withScope(Scope $scope)
返回应用了给定作用域的对象的副本。
->scopeRaw()
返回应用了原始作用域的对象的副本。原始作用域移除所有行为。
->scopeFull()
返回应用了完整作用域的对象的副本。完整作用域保留所有行为。这是默认作用域,除非您在仓库的 setup() 方法中更改作用域。
示例
final class AdminScope implements \Efabrica\NetteRepository\Repository\Scope\Scope { public function apply(RepositoryBehaviors $behaviors, Repository $repository): void { // Remove these behaviors because they are not needed for the Admin $behaviors ->remove(SoftDeleteBehavior::class) ->remove(PublishBehavior::class); // Do not add any new behaviors here, because this scope can be used by different repositories // and you might introduce unwanted side effects. // However, you can conditionally add behaviors based on the repository type and some parameter // For example, if you want to apply a special behavior for admin users in the user repository, you can do this: if ($repository instanceof UserRepository && $someContainerParameter) { // Scopes can be services and receive parameters. $behaviors->add(AdminBehavior::class); // This is a hypothetical behavior, just for illustration. } } }
要使用作用域作为 容器服务(在某些情况下可能不是必需的),请按照以下步骤操作
use Efabrica\NetteRepository\Repository\RepositoryBehaviors; abstract class RepositoryBase extends \Efabrica\NetteRepository\Repository\Repository { /** @inject */ public AdminScope $adminScope; public function scopeAdmin(): self { return $this->withScope($this->adminScope); } // Do this if you want to set the AdminScope as default: protected function setup(RepositoryBehaviors $behaviors) : void { $behaviors->setScope($this->adminScope); } }
并且 可选 实现查询的简写方法
use YourBeautifulApplication\Admin\AdminScope; abstract class QueryBase extends \Efabrica\NetteRepository\Repository\Query { public function scopeAdmin(): self { // This method returns a copy of the query with your own Admin scope applied // The Admin scope removes some behaviors that are not relevant for the Admin return $this->withScope($this->repository->adminScope); // Alternatively, if the Admin scope does not depend on any parameters, you can create a new instance of it like this: return $this->withScope(new AdminScope()); } }
用法
// all of these are equivalent: $repository->findBy(['age > ?' => 18])->scopeAdmin()->fetchAll(); $repository->scopeAdmin()->findBy(['age > ?' => 18])->fetchAll(); $repository->query()->where('age > ?', 18)->scopeAdmin()->fetchAll(); $repository->scopeAdmin()->query()->where('age > ?', 18)->fetchAll(); $repository->query()->scopeAdmin()->where('age > ?', 18)->fetchAll();
代码生成器
代码生成是可选的,但建议使用它。
要运行代码生成,请使用此命令
$ php bin/console efabrica:nette-repo:code-gen # OR $ php bin/console e:n:c # OR $ php vendor/bin/enc
对于数据库中的每个表,它将在 /Generated/
命名空间中生成以下类:(例如:person
表)
Repository\Generated\Repository\PersonRepositoryBase
- 仓库基类,包含PersonQuery
和Person
实体的类型提示。(抽象)Repository\Generated\Query\PersonQuery
- 查询类,包含Person
实体的类型提示。(抽象)Repository\Generated\Entity\Person
- 实体类,包含列的类型和列名称的公共常量。(最终)
当您运行代码生成器时,这些类将始终重新生成。它们不应手动修改。
对于数据库中的每个表,它还会生成以下类 在 /Generated/
命名空间之外,但仅当它们不存在时。如果它们存在,则不会覆盖。
Repository\PersonRepository
- 扩展PersonRepositoryBase
。在这里编写您自定义的仓库方法。(最终)Repository\Query\PersonQuery
- 扩展PersonQuery
。在这里编写您自定义的查询方法。(最终)Repository\Entity\PersonBody
- 插入到Person
实体的特质。在这里编写您自定义的实体方法。(特质)
当您运行代码生成器时,这些类 不会重新生成。它们旨在由您自定义。如果您想重新生成它们,您必须先删除它们。
忽略表
也可以忽略一些表格。要这样做,您可以修改配置文件中的 ignoredTables
参数
netteRepo:
ignoreTables:
# These are the defaultly ignored tables:
migrations: true
migration_log: true
phoenix_log: true
phinxlog: true
自定义继承
如果您想为生成的类设置不同的 extends
或 implements
,您可以通过在您的配置文件中添加条目来实现
netteRepo: inheritance: AuthorRepositoryBase: extends: 'App\Repository\PeopleRepositoryBase' implements: ['App\Repository\PersonRepositoryInterface'] AuthorQuery: extends: 'App\Repository\PeopleQueryBase' Person: implements: ['App\Repository\PersonInterface']
- 每个生成的类都可以用于此。
- 键是简短类名(不包含命名空间)。生成的类设计为没有命名空间冲突,所以这不应该是一个问题。
extends
必须是字符串或 null/未指定。implements
必须是字符串数组或空数组或 null/未指定。- 您不能取消实现一个接口。
此配置模式有点冗长,但一旦您看到它,就非常直观,且易于阅读。
行为和特性
DateBehavior
此行为自动将 created_at
和 updated_at
列设置为插入或更新行时的当前日期和时间。
FilterBehavior
此行为将默认的 where() 条件应用到每个 select 查询中。
KeepDefaultBehavior
此行为确保在默认列中始终至少有一行具有真值。这对于标志列很有用。
SoftDeleteBehavior
此行为通过将 deleted_at
列设置为当前日期和时间来标记行已删除,而不是从表中删除它。
LastManStandingBehavior
此行为防止删除匹配给定查询的表中最后一行。
TreeTraverseBehavior
此行为管理表示表层次结构的 lft
和 rgt
列。它在插入或更新行时自动更新它们。
SortingTrait
此特性为存储库添加了更改行顺序的方法,例如 moveUp()、moveDown()、insertBefore() 和 insertAfter()。
CastBehavior
此行为在从数据库检索值时自动将值转换为指定的类型。
有一些预定义的转换,但您也可以定义自己的。
JsonCastBehavior
:将值从 JSON 转换为 PHP 数组,反之亦然。CarbonCastBehavior
:将值从 MySQL datetime 转换为 CarbonImmutable,反之亦然。
事件
在您的存储库中可以监听几个事件:Insert、Update、Delete、Select、Load
要实现您自己的事件订阅者,创建一个新的类,它扩展了 Efabrica\NetteRepository\Subscriber\EventSubscriber
并在容器中注册它。由于它扩展了 EventSubscriber,它将自动被检测到。