weavora / doctrine-extensions
Doctrine2 ORM 扩展
Requires
- php: >=5.3.3
- doctrine/orm: >=2.2.3,<2.4-dev
Requires (Dev)
- mockery/mockery: dev-master@dev
This package is not auto-updated.
Last update: 2024-09-23 15:18:18 UTC
README
此库通过一些有用的功能扩展了 Doctrine2 基础类。
安装
您可以使用 Composer 或从其 GitHub 仓库克隆它来安装此库。以下将描述这两种选项。
Composer
您可以在 https://packagist.org.cn 上了解更多关于 Composer 和其主要仓库的信息。要使用 Composer 安装这些 doctrine 扩展,首先根据 Packagist 主页上的说明安装您的项目中的 Composer。然后,您可以使用以下建议的参数定义对 doctrine-extensions 的开发依赖。虽然我们尽力保持主分支的稳定性,但您可能更喜欢使用当前的稳定版本标签。
{
"require-dev": {
"weavora/doctrine-extensions": "dev-master@dev"
}
}
要安装,您可以调用
composer.phar install
Git / GitHub
git 仓库在其 master 分支中托管开发版本。您可以通过在项目的 composer.json 文件中将 dev-master 作为您首选的版本来引用,如前面的示例所示,使用 Composer 安装它。
您也可以安装此开发版本
git clone git://github.com/weavora/doctrine-extensions.git
cd doctrine-extensions
上述过程将库安装到 doctrine-extensions 文件夹中。
ORM 扩展
Doctrine 建议使用包含与实体检索相关的业务逻辑的实体仓库。您很可能会在仓库中使用查询构建器来构建 DQL。问题是标准查询构建器具有相当通用的 API,并且不提供诸如命名范围、应用自定义条件参数的单个方法等有用的快捷方式。
此库旨在填补这些空白,使您的生活更加轻松。
如何组织仓库
假设您想创建一个博客应用程序。您可能会创建一个帖子实体,它将引用类别、作者和评论。现在您正在考虑组织仓库的方法。
仓库的常见问题
- 一旦有重复的条件,就必须重复代码
- 即使简单的具有少量条件和排序的方法看起来也很庞大
您可以通过为每个实体创建自定义查询构建器来解决第一个问题。它还将隐藏您的条件细节,这些细节对于不需要真正知道这些的仓库来说并不重要。
为了解决庞大且不太描述性的方法的难题,您将创建一个查询构建器的扩展,其中包含一些有用的快捷方式,使代码更易于阅读。
PostQueryBuilder & PostRepository 可能的样子示例
<?php namespace Acme\BlogBundle\Entity; use Weavora\Doctrine\ORM as ORM; /** * Custom query class for Post entity * Contains useful criteria set for posts filtering */ class PostQueryBuilder extends ORM\EntityQueryBuilder { public function published() { return $this->filterByColumn('Post.publishStatus', Post::STATUS_PUBLISHED); } public function recentFirst() { return $this->orderBy('Post.publishedAt', 'DESC'); } } /** * Post entity repository * Contains methods for fetch posts */ class PostRepository extends ORM\EntityRepository { /** * Instantiate custom query builder * @return PostQueryBuilder */ public function filter() { return new PostQueryBuilder($this->getEntityManager(), $this); } /** * Find 10 recent posts * * @return Post[] */ public function findRecent() { return $this ->filter() // use PostQueryBuilder ->published() // get only published posts ->limit(10) // get only first 10 posts ->recentFirst() // most recent posts should go first ->fetchAll(); // get posts } /** * Find posts by category * * @param Category $category * @param int $page * @param int $itemsPerPage * @return Post[] */ public function findByCategory(Category $category, $page = 1, $itemsPerPage = 10) { return $this ->filter() // use PostQueryBuilder ->filterByColumn('Post.category', $category) // get only posts in the specified category ->paginate($page, $itemsPerPage) // get only the specified page ->recentFirst() // most recent posts should go first ->fetchAll(); // get posts } /** * Count posts by author * * @param Author $author * @return int */ public function countByAuthor(Author $author) { return $this ->filter() // use PostQueryBuilder ->select('COUNT(Post.id)') // calculate count ->filterByColumn('Post.author', $author) // calculate only author's posts ->groupBy('Post.author') // group by author ->fetchScalar(); // get scalar results (the first column of the first row) } }
很简单,对吧?
API / EntityQueryBuilder
getEntityAlias() : string | 获取查询中的实体别名
// entity class name -> alias // \Entity\Post -> Post // \Acme\DemoBundle\Entity\AuthorSettings -> AuthorSettings // \Comment -> Comment $alias = $queryBuilder->getEntityAlias();
filterByColumn($columnName, $value, $strict = true) : EntityQueryBuilder | 将列与指定的值进行比较
// SELECT * FROM Entity\Post Post WHERE Post.title = :p1, [p1 = 'Post 1'] $queryBuilder->filterByColumn('Post.title', 'Post 1'); // SELECT * FROM Entity\Post Post WHERE Post.category IN (1,2,3) $queryBuilder->filterByColumn('Post.category', array(1,2,3)); // SELECT * FROM Entity\Post Post WHERE Post.author IS NULL $queryBuilder->filterByColumn('Post.author', null); // SELECT * FROM Entity\Post Post $queryBuilder->filterByColumn('Post.author', null, false); // SELECT * FROM Entity\Post Post WHERE Post.author = 1 $queryBuilder->filterByColumn('Post.author', 1, false);
filterByStatement($statement, $parameters = array()) : EntityQueryBuilder | 添加自定义语句
// SELECT * FROM Entity\Post Post WHERE Post.title = :title, [title = 'Post 1'] $queryBuilder->filterByStatement('Post.title = :title', ['title' => 'Post 1']); // SELECT * FROM Entity\Post Post WHERE Post.category IN (1,2,3) $queryBuilder->filterByColumn('Post.category IN (1,2,3)');
limit($maxResults, $offset = null) : EntityQueryBuilder | 限制结果
// SELECT * FROM Entity\Post Post LIMIT 0, 10 $queryBuilder->limit(10); // SELECT * FROM Entity\Post Post LIMIT 15, 10 $queryBuilder->limit(10, 15);
fetchAll($parameters = array()) : EntityClass[] | 获取结果
// SELECT * FROM Entity\Post Post -> Post[] $queryBuilder->fetchAll(); // SELECT * FROM Entity\Post Post LIMIT 0, 10 -> Post[] $queryBuilder->filterByStatement('Post.title = :title')->fetchAll(['title' => 'Post 1']);
fetchOne($parameters = array()) : EntityClass | 获取第一个结果
// SELECT * FROM Entity\Post Post LIMIT 0, 1 -> Post $queryBuilder->fetchOne();
fetchScalar($parameters = array()) : int|string|float|null | 获取标量结果
// SELECT COUNT(*) FROM Entity\Post Post LIMIT 0, 1 -> int $queryBuilder->select('COUNT(*)')->fetchScalar();
DBAL 扩展
对DBAL类只有一个小的增强 - Connection::lockSafeUpdate
,允许你在事务被锁定并失败的情况下重新启动查询。也许,这会展示如何通过自定义方法扩展Doctrine连接类。
如何配置
# config.yml doctrine: dbal: wrapper_class: 'Weavora\Doctrine\DBAL\Connection'
使用示例
// Method will retry a query if it failed because of lock the first time
// You can specify the retry number as the 3rd argument
$doctrine->getConnection()->locksSafeUpdate("UPDATE posts SET category_id = :category", ['category' => 2]);
关于
稳定性
目前还不稳定。请自行承担使用风险。
要求
- PHP 5.3或更高版本中的任何版本都应该可以
- [可选] PHPUnit 3.5+ 执行测试套件(phpunit --version)
提交错误和功能请求
错误和功能请求在GitHub上跟踪
作者
Weavora LLC - http://weavora.com - http://twitter.com/weavora
还可以查看参与此项目的贡献者列表。
许可
此库采用MIT许可 - 详细信息请参阅LICENSE
文件