alex-unruh / repository
基于Doctrine DBAL查询构建器的抽象层
Requires
- php: >=7.2
- doctrine/dbal: ^3.3
This package is auto-updated.
Last update: 2024-09-13 19:07:32 UTC
README
这是一个扩展Doctrine DBAL查询构建器的抽象层,提供了帮助减少绑定值代码量的方法,例如。
安装
composer require alex-unruh/repository
用法
下面是一个使用Doctrine DBAL QueryBuilder进行插入查询的场景示例
// index.php use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Query\QueryBuilder; $conn = DriverManager::getConnection($connection_params); $query_builder = $conn->createQueryBuilder(); $query_builder->insert('users') ->setValue('Name', '?') ->setValue('CountryCode', '?') ->setValue('District', '?') ->setValue('Population', '?') ->setParameter(0, 'Osasco') ->setParameter(1, 'BRA') ->setParameter(2, 'São Paulo') ->setParameter(3, '800000') ->executeStatement();
现在让我们看看使用Repository::class进行相同查询的抽象化示例
// index.php use AlexUnruh\Repository; $repo = new Repository($connection_params); $repo->insert('city') ->addvalues(['Name' => 'Osasco', 'CountryCode' => 'BRA', 'District' => 'São Paulo', 'Population' => '800000']) ->execute();
在幕后,仓库类执行的是完全相同的程序,安全地进行绑定并返回相同的结果。如果你有一个大表,这将非常有用。实际上,Doctrine DBAL Query Builder中所有的方法都存在于Repository::class中,因为,正如我们已经说过的,它扩展了DBAL QB。你可以自由地使用它们。
父类(Doctrine DBAL QueryBuilder)中不存在的方法
setConnection(array $connection_params): Repository
如果你需要在多个查询中使用相同的连接,如事务,这非常有用
//index.php use AlexUnruh\Repository; $conn = DriverManager::getConnection($connection_params); $conn->transactional({ $repo = new Repository(); $repo->setConnection($conn); $repo->select('author_id')->from('posts')->where('slug = :slug')->setParameter('slug', 'my-post'); $result = $repo->getFirst(); $id = $result['author_id']; $repo->resetQueryParts(); $repo->update('users')->setValues(['best_post' => true])->where("id = {$id}")->execute(); });
get()
用于select语句的末尾,返回多维数组
// index.php use AlexUnruh\Repository; $repo = new Repository($connection_params); $repo->select('*')->from('users')->get(); // Returns /* [ [ 'id' => '1', 'name' => 'Foo', 'username' => 'Bar, 'password' => 'foobar' ], [ 'id' => '2', 'name' => 'Bar', 'username' => 'Foo, 'password' => 'barfoo' ], ] */
getFirst()
用于select语句的末尾,只返回查询的第一个结果
// index.php use AlexUnruh\Repository; $repo = new Repository($connection_params); $repo->select('*')->from('users')->getFirst(); // Returns /* [ 'id' => '1', 'name' => 'Foo', 'username' => 'Bar, 'password' => 'foobar' ] */
addValues(array $array_data)
- @param array $array_data = 包含要插入到表中的键 => 值对的数组
// index.php use AlexUnruh\Repository; $repo = new Repository($connection_params); $repo->insert('users')->addValues(['name' => 'Foo', 'email' => 'foo@bar.com', 'pass' => $encripted_pass])->execute();
setValues(array $array_data)
- @param array $array_data = 包含要更新到表中的键 => 值对的数组
// index.php use AlexUnruh\Repository; $repo = new Repository($connection_params); $repo->update('users')->setValues(['name' => 'Foo', 'email' => 'foo@bar.com', 'pass' => $encripted_pass])->execute();
execute()
execute方法负责在插入、更新和删除语句中安全地绑定参数,并返回受影响的行数。它通过调用Doctrine DBAL父类的setParameters()和executeStatement()方法来实现。
// index.php use AlexUnruh\Repository; $repo = new Repository($connection_params); $repo->update('users')->setvalues(['name' => 'New Name'])->execute();
尽管不可见,但在setValues和execute方法之间将存在一个bindParam
setTypes(array $types): Repository
- @param array $types = 包含要用于需要指定要插入或更新的数据类型的查询的键 => 值对的数组。请参阅Doctrine DBAL文档中的更多内容
在某些情况下,当你在Doctrine DBAL或其他查询构建器中工作时,需要设置特定列数据的类型。例如,如果你在一个表中存储加密数据,可能需要告诉查询构建器这种数据的类型,因为每种类型的数据库以不同的方式存储这种数据。
在其他情况下,出于安全考虑,在存储之前需要设置值的类型,在setParameter方法中。如果类型与定义的不同,将抛出异常。
让我们看看使用Doctrine DBAL QueryBuilder的示例
// index.php use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Query\QueryBuilder; $conn = DriverManager::getConnection($connection_params); $query_builder = $conn->createQueryBuilder(); $query_builder->insert('posts') ->setValue('name', ?) ->setValue('slug', ?) ->setValue('author_id', ?) ->setValue('image', ?) ->setParameter(0, $post_name, 'string') ->setparameter(1, $slug, 'string') ->setparameter(2, $author_id, 'integer') ->setparameter(3, $encrypted_data, 'blob') ->executeSatetment();
现在,让我们看看使用Repository::class的示例
// index.php use AlexUnruh\Repository; $repo = new Repository($connection_params); $repo->setTypes(['name' => 'string', 'slug' => 'string', 'author_id' => 'string', 'image' => 'blob']); $repo->insert('posts') ->addValues(['name' => $post_name, 'slug' => $slug, 'author_id' => $author_id. 'image' => $encripted_data]) ->execute();
扩展Repository::class
大多数查询可以使用父仓库类中的方法执行。但在某些情况下,你可能会有更复杂的查询(例如包含子查询的查询),这会使你的控制器“膨胀”,并且你希望将这些查询放在单独的类中,使用仓库模式。为此,你可以创建自己的类并扩展父仓库类。
所有继承自Repositor::class的类都需要至少有一个受保护的$table_name属性,才能使用以下将要描述的特殊CRUD方法。
继承类可以实现的另一个参数是$data_types,它包含上面setTypes方法中描述的数据类型。
不要浪费时间试图理解下面的方法。虽然它可行,但这里只是为了演示Repository模式的用法。
// MyRepo.php use AlexUnruh\Repository; class MyRepo extends Repository { protected $table_name = 'images'; protected $data_types = []; /** * Remember, we are extending the Query Builder class, so we use "$this" here */ public function lockRecord(int $status) { $id = uniqid(rand(), true); $now = date('Y-m-d H:i:s'); $max_time = date('Y-m-d H:i:s', strtotime('+5 minutes', strtotime($now))); $subquery = $this->select('uuid') ->distinct() ->from('another_table') ->where('status = ?') ->setMaxResults(1) ->getSQL(); $this->resetQueryParts(); $this->modify(['time_lock' => "'$max_time'", 'id_lock' => $id]) ->where("id_lock = 0 OR time_lock < '{$now}'") ->andwhere('cancel = 0') ->andWhere('status = ?') ->andWhere("uuid IN ($subquery)") ->setParameter(0, $status) ->setParameter(1, $status); return $this->execute() ? true : false; } } // index.php $repo = new MyRepo($connection_params); $repo->lockRecord(1);
仅适用于扩展类的可用方法:读取、创建、修改和删除。
以下所有方法都需要在继承自Repositor::class的类中使用,因为它们使用了这些类中定义的参数,例如$table_name或$data_types。
read(array $data, string $table_alias = null): Repository
- @param array $array_data = 包含要从表中选择的数据的数组
- @param string $table_alias = 在连接语句中使用的表别名(可选)
// index.php // example 1 $user = new UserRepo($connection_params); $result = $user->read(['name', 'username'])->where('id' => 5)->getFirst(); // example 2 (With table alias an join) $user = new UserRepo($connection_params); // second parameter "a" is the table alias to users table $user->read(['a.name as author', 'b.*'], 'a') ->join('a', 'posts', 'b', 'b.author_id' = 'a.id') ->where('a.id = :id') ->setparameter('id', $id); $result = $user->get();
create(array $data): Repository
- @param array $array_data = 包含要插入到表中的键 => 值对的数组
在幕后,repository::class将会使用$data_types数组安全地绑定值到每个列,如果这些值存在于类属性中。
// index.php $user = new UserRepo($connection_params); $user->create(['name' => 'Foo', 'email' => 'foo@bar.com', 'pass' => $encripted_pass])->execute();
modify(array $data, string $table_alias = null): Repository
- @param array $array_data = 包含要更新到表中的键 => 值对的数组
- @param string $table_alias = 在连接语句中使用的表别名(可选)
在幕后,repository::class将会使用$data_types数组安全地绑定值到每个列,如果这些值存在于类属性中。始终与WHERE子句一起使用。
//index.php $user = new UserRepo($connection_params); $user->modify(['name' => 'Foo', 'email' => 'foo@bar.com', 'pass' => $encripted_pass])->where('id = :id')->addParameter('id', $id)->execute();
destroy(string $table_alias = null): Repository
- @param string $table_alias = 在连接语句中使用的表别名(可选)
// index.php $user = new UserRepo($connection_params); $user->destroy()->where('id = :id')->setParameter('id', $id, 'integer')->execute();
addParameter(string $key, string $val, string $type = null): Repository
- @param string $key = 参数键
- @param string $val = 参数值
- @param string $type = 参数类型
此方法建议在您使用modify方法并需要在其他子句(如WHERE子句)中绑定新参数时使用。
// index.php $user = new UserRepo($connection_params); $user->modify(['name' => 'Foo', 'email' => 'foo@bar.com', 'pass' => $encripted_pass])->where('id = :id')->addParameter('id', $id)->execute();
享受吧。