aternos / model
简单和复杂数据库模型的PHP库
Requires
- php: >=8.0
- ext-json: *
Requires (Dev)
- elasticsearch/elasticsearch: ^7.10
- phpunit/phpunit: ^10.2
Suggests
- ext-cassandra: To use the Cassandra NoSQL driver
- ext-mysqli: To use the Mysqli Relational driver
- ext-redis: To use the Redis Cache driver
- elasticsearch/elasticsearch: To use the Elasticsearch Search driver
README
简单和复杂数据库模型的PHP库。
关于
此库是为了提供一个灵活但易于使用的模型系统而创建的,它可以用于新项目,也可以集成到现有项目中。库的每个部分都可以单独覆盖和替换,以实现自定义逻辑。
与其他模型库相比,此库不绑定到任何特定的数据库后端,而是每个模型都可以包含用于访问不同数据库的定制逻辑,例如用于不同的缓存或搜索后端。因此,此库不提供任何配置功能。
注意:此库仍在开发中,特别是关于更多驱动程序功能的一些功能将在未来添加。
安装
composer require aternos/model
基本用法
驱动
该库包含一些驱动程序,但您也可以创建自己的驱动程序并在项目中使用它们,或将它们提交以添加到库中。
当前包含的驱动程序包括
所有这些驱动程序都需要额外的扩展或包,请参阅 composer.json 中的 "suggest"。
大多数驱动程序可以在没有密码的本地数据库设置中直接工作,但对于大多数用例,您必须使用不同的凭据。要使用包含的驱动程序执行此操作,您可以通过构造函数创建一个新实例并设置凭据
$driver = new \Aternos\Model\Driver\Mysqli\Mysqli("localhost", 3306, "username", "password");
或使用流畅设置器
$driver = (new \Aternos\Model\Driver\Mysqli\Mysqli())->setUsername("username")->setPassword("password");
或创建一个新的驱动程序类,扩展库驱动程序并覆盖受保护的凭据属性(在类本身或在构造函数中),例如
<?php namespace MyModel; class Mysqli extends \Aternos\Model\Driver\Mysqli\Mysqli { protected ?string $user = 'username'; protected ?string $password = 'password'; public function __construct(?string $host = null, ?int $port = null, ?string $username = null, ?string $password = null, ?string $socket = null, ?string $database = null) { parent::__construct($host, $port, $username, $password, $socket, $database); $this->host = \Config::getHost(); } }
之后,您必须在 DriverRegistry 中注册该类
<?php \Aternos\Model\Driver\DriverRegistry::getInstance()->registerDriver($driver); // or using your own class \Aternos\Model\Driver\DriverRegistry::getInstance()->registerDriverClass(\MyModel\Mysqli::ID, \MyModel\Mysqli::class);
所有驱动程序都有一个用于标识和(如果需要)覆盖现有驱动程序的ID。通常建议为每种驱动程序类型使用唯一的ID,但如果您需要同一类型的多个驱动程序(例如,如果您有两个不同的MySQL数据库),则可以创建和注册具有不同ID的多个驱动程序。您可以使用任何驱动程序上的 setId()
流畅设置器或通过覆盖您自己的类中的 getId()
函数来设置ID。
<?php $driverA = (new \Aternos\Model\Driver\Mysqli\Mysqli())->setId("mysqli-a")->setHost("a.mysql.host"); \Aternos\Model\Driver\DriverRegistry::getInstance()->registerDriver($driverA); $driverB = (new \Aternos\Model\Driver\Mysqli\Mysqli())->setId("mysqli-b")->setHost("b.mysql.host"); \Aternos\Model\Driver\DriverRegistry::getInstance()->registerDriver($driverB);
模型
现在您可以创建一个模型类。所有模型类都必须遵循 ModelInterface。此库包含两个不同的抽象模型类,以简化模型创建
- BaseModel - 实现基本模型逻辑,与任何驱动程序无关
- GenericModel - 可选实现所有驱动程序和注册表
建议从 GenericModel 开始,因为它已经实现了多个驱动程序,并且您可以为每个模型或所有模型(通过使用您自己的父模型为所有模型)启用所需的驱动程序。
这是一个使用Mysqli数据库作为后端和缓存的示例实现,使用GenericModel。驱动配置是一个有序数组$drivers
,包含驱动ID,第一个驱动首先用于获取模型。其他操作的驱动依赖于$drivers
数组(例如,对于save()
和delete()
是逆序的),但可以单独配置,例如设置$saveDrivers
数组。
<?php class User extends \Aternos\Model\GenericModel { // use model registry (default: true) protected static bool $registry = true; // cache the model for 60 seconds (default: null) protected static ?int $cache = 60; // configure the generic model drivers (this is the default) protected static array $drivers = [ \Aternos\Model\Driver\Redis\Redis::ID, \Aternos\Model\Driver\Mysqli\Mysqli::ID ]; // the name of your model (and table) public static function getName() : string { return "users"; } // all public properties are database fields public $id; public $username; public $email; }
使用您的模型
现在您可以在代码中使用您的模型
<?php // create new user $user = new User(); $user->username = "username"; $user->email = "mail@example.org"; $user->save(); // get a user by id $user = User::get($id); echo $user->username; // you can force to skip the registry and the cache $user = User::get($id, true); // update a user $user->email = "othermail@example.org"; $user->save(); // delete a user $user->delete();
查询
您可以使用Query对象查询模型,例如SelectQuery。它允许不同的语法可能性,例如将简单的数组/字符串/整型值直接传递给构造函数,或者基于Query/...类构建所有参数。所有查询都返回一个QueryResult对象,该对象是可迭代的并可计数的。
选择
<?php // the following lines are all the same User::select(["email" => "mail@example.org"]); // ::select() is only a helper function of GenericModel User::query(new \Aternos\Model\Query\SelectQuery(["email" => "mail@example.org"])); User::query((new \Aternos\Model\Query\SelectQuery())->where(["email" => "mail@example.org"])); User::query(new \Aternos\Model\Query\SelectQuery( new \Aternos\Model\Query\WhereCondition("email", "mail@example.org") )); User::query(new \Aternos\Model\Query\SelectQuery( new \Aternos\Model\Query\WhereGroup([ new \Aternos\Model\Query\WhereCondition("email", "mail@example.org") ]) )); // use the result $userQueryResult = User::select(["email" => "mail@example.org"]); if (!$userQueryResult->wasSuccessful()) { echo "Query failed"; } echo "Found " . count($userQueryResult) . " users"; foreach($userQueryResult as $user) { /** @var User $user */ echo $user->username; } // another query example User::select( ["field" => "value", "hello" => "world", "foo" => "bar"], ["field" => "ASC", "hello" => "DESC", "foo" => "ASC"], ["field", "hello", "foo"], [100, 10] ); // can also be written as User::query((new \Aternos\Model\Query\SelectQuery) ->where(["field" => "value", "hello" => "world", "foo" => "bar"]) ->orderBy(["field" => "ASC", "hello" => "DESC", "foo" => "ASC"]) ->fields(["field", "hello", "foo"]) ->limit([100, 10]) ); // a more complex query with nested where groups using the query parameter classes User::query(new \Aternos\Model\Query\SelectQuery( new \Aternos\Model\Query\WhereGroup([ new \Aternos\Model\Query\WhereCondition("field", "value", "<>"), new \Aternos\Model\Query\WhereGroup([ new \Aternos\Model\Query\WhereCondition("hello", "world"), new \Aternos\Model\Query\WhereCondition("foo", "bar") ], \Aternos\Model\Query\WhereGroup:: OR) ]), [ new \Aternos\Model\Query\OrderField("field", \Aternos\Model\Query\OrderField::DESCENDING), new \Aternos\Model\Query\OrderField("hello", \Aternos\Model\Query\OrderField::ASCENDING), new \Aternos\Model\Query\OrderField("foo", \Aternos\Model\Query\OrderField::DESCENDING) ], [ new \Aternos\Model\Query\SelectField("field"), new \Aternos\Model\Query\SelectField("hello"), new \Aternos\Model\Query\SelectField("foo") ], new \Aternos\Model\Query\Limit(10, 100) ));
更新
<?php // update mail to "mail@example.org" where username is "username" User::query(new \Aternos\Model\Query\UpdateQuery(["email" => "mail@example.org"], ["username" => "username"])); User::query((new \Aternos\Model\Query\UpdateQuery()) ->fields(["email" => "mail@example.org"]) ->where(["username" => "username"])); User::query(new \Aternos\Model\Query\UpdateQuery( new \Aternos\Model\Query\UpdateField("email", "mail@example.org"), new \Aternos\Model\Query\WhereCondition("username", "username") )); User::query(new \Aternos\Model\Query\UpdateQuery( [new \Aternos\Model\Query\UpdateField("email", "mail@example.org")], new \Aternos\Model\Query\WhereGroup([ new \Aternos\Model\Query\WhereCondition("username", "username") ]) ));
删除
<?php // delete where email is mail@example.org User::query(new \Aternos\Model\Query\DeleteQuery(["email" => "mail@example.org"])); User::query((new \Aternos\Model\Query\DeleteQuery())->where(["email" => "mail@example.org"])); User::query(new \Aternos\Model\Query\DeleteQuery( new \Aternos\Model\Query\WhereCondition("email", "mail@example.org") )); User::query(new \Aternos\Model\Query\DeleteQuery( new \Aternos\Model\Query\WhereGroup([ new \Aternos\Model\Query\WhereCondition("email", "mail@example.org") ]) ));
测试
此库包含一个TestDriver
,可用于在不使用数据库的情况下编写测试。它使用一个简单的数组作为存储,并且不是持久的。它支持大多数基本操作和查询,但可能尚不支持所有用例,特别是特定于数据库的查询。
您可以直接向模型添加测试数据,这将同时启用该模型的测试驱动程序。
<?php // add a single entry User::addTestEntry([ "id" => 1, "name" => "Test", "email" => "test@example.org" ]); // add multiple entries at once User::addTestEntries($entries); // clear all test entries User::clearTestEntries();
或者,您也可以直接向测试驱动程序添加数据。
/** @var \Aternos\Model\Driver\Test\TestDriver $testDriver */ $testDriver = \Aternos\Model\Driver\DriverRegistry::getInstance()->getDriver(\Aternos\Model\Driver\Test\TestDriver::ID); // add multiple tables at once $testDriver->addTables([ "user" => [ [ "id" => 1, "name" => "Test", "email" => "test@example.org" ], ... ], "another_table" => [ [ "id" => 1, ... ] ], ... ]); // add a single table $testDriver->addTable("user", [ [ "id" => 1, "name" => "Test", "email" => "test@example.org" ], ... ]); // add an entry to a table $testDriver->addEntry("user", [ "id" => 1, "name" => "Test", "email" => "test@example.org" ]); // clear all entries from a table $testDriver->clearEntries("user"); // clear all tables $testDriver->clearTables();
如果您直接向驱动程序添加数据,您仍然需要为每个想要测试的模型启用测试驱动程序。
<?php // enable the test driver for the user model User::enableTestDriver(); // you can enable the test driver for all models at once by enabling it on a shared parent class MyModel extends Aternos\Model\GenericModel {} class User extends MyModel { ... } class AnotherModel extends MyModel { ... } MyModel::enableTestDriver();
高级用法
有关编写自己的驱动程序、驱动程序工厂或模型的更多信息,将在未来添加,同时请查看源代码。