Completed
Push — master ( 07aed8...2affeb )
by Julián
05:59
created

RelationalRepository::paginate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
1
<?php
2
3
/*
4
 * doctrine-orm-repositories (https://github.com/juliangut/doctrine-orm-repositories).
5
 * Doctrine2 ORM utility entity repositories.
6
 *
7
 * @license MIT
8
 * @link https://github.com/juliangut/doctrine-orm-repositories
9
 * @author Julián Gutiérrez <[email protected]>
10
 */
11
12
declare(strict_types=1);
13
14
namespace Jgut\Doctrine\Repository\ORM;
15
16
use Doctrine\Common\Util\ClassUtils;
17
use Doctrine\ORM\EntityManager;
18
use Doctrine\ORM\EntityRepository;
19
use Doctrine\ORM\Query;
20
use Doctrine\ORM\QueryBuilder;
21
use Doctrine\ORM\Tools\Pagination\Paginator as RelationalPaginator;
22
use Jgut\Doctrine\Repository\EventsTrait;
23
use Jgut\Doctrine\Repository\PaginatorTrait;
24
use Jgut\Doctrine\Repository\Repository;
25
use Jgut\Doctrine\Repository\RepositoryTrait;
26
use Rb\Specification\Doctrine\SpecificationAwareInterface;
27
use Rb\Specification\Doctrine\SpecificationRepositoryTrait;
28
use Zend\Paginator\Paginator;
29
30
/**
31
 * Relational entity repository.
32
 */
33
class RelationalRepository extends EntityRepository implements Repository, SpecificationAwareInterface
34
{
35
    use SpecificationRepositoryTrait;
36
    use RepositoryTrait;
37
    use EventsTrait;
38
    use PaginatorTrait;
39
40
    /**
41
     * Class alias.
42
     *
43
     * @var string
44
     */
45
    protected $classAlias;
46
47
    /**
48
     * Get class alias.
49
     *
50
     * @return string
51
     */
52
    protected function getClassAlias(): string
53
    {
54
        if ($this->classAlias === null) {
55
            $this->classAlias = strtoupper($this->getEntityName()[0]);
56
        }
57
58
        return $this->classAlias;
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function getClassName(): string
65
    {
66
        return ClassUtils::getRealClass(parent::getClassName());
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    protected function getManager(): EntityManager
73
    {
74
        return $this->getEntityManager();
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     *
80
     * @param array|QueryBuilder $criteria
81
     * @param array|null         $orderBy
82
     * @param int                $itemsPerPage
83
     *
84
     * @throws \InvalidArgumentException
85
     *
86
     * @return \Zend\Paginator\Paginator
87
     */
88
    public function findPaginatedBy($criteria, array $orderBy = [], int $itemsPerPage = 10): Paginator
89
    {
90
        $queryBuilder = $this->createQueryBuilderFromCriteria($criteria);
91
        $entityAlias = count($queryBuilder->getRootAliases())
92
            ? $queryBuilder->getRootAliases()[0]
93
            : $this->getClassAlias();
94
95
        if (is_array($orderBy)) {
96
            foreach ($orderBy as $field => $order) {
97
                $queryBuilder->addOrderBy($entityAlias . '.' . $field, $order);
98
            }
99
        }
100
101
        return $this->paginate($queryBuilder->getQuery(), $itemsPerPage);
102
    }
103
104
    /**
105
     * Paginate query.
106
     *
107
     * @param Query $query
108
     * @param int   $itemsPerPage
109
     *
110
     * @return Paginator
111
     */
112
    protected function paginate(Query $query, int $itemsPerPage = 10) : Paginator
113
    {
114
        return $this->getPaginator(new RelationalPaginatorAdapter(new RelationalPaginator($query)), $itemsPerPage);
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     *
120
     * @param array|QueryBuilder $criteria
121
     *
122
     * @throws \InvalidArgumentException
123
     *
124
     * @return int
125
     */
126
    public function countBy($criteria): int
127
    {
128
        $queryBuilder = $this->createQueryBuilderFromCriteria($criteria);
129
        $entityAlias = count($queryBuilder->getRootAliases())
130
            ? $queryBuilder->getRootAliases()[0]
131
            : $this->getClassAlias();
132
133
        return (int) $queryBuilder
134
            ->select('COUNT(' . $entityAlias . ')')
135
            ->getQuery()
136
            ->getSingleScalarResult();
137
    }
138
139
    /**
140
     * Create query builder based on provided simple criteria.
141
     *
142
     * @param array|QueryBuilder $criteria
143
     *
144
     * @throws \InvalidArgumentException
145
     *
146
     * @return QueryBuilder
147
     */
148
    protected function createQueryBuilderFromCriteria($criteria): QueryBuilder
149
    {
150
        if ($criteria instanceof QueryBuilder) {
151
            return $criteria;
152
        }
153
154
        if (!is_array($criteria)) {
155
            throw new \InvalidArgumentException(sprintf(
156
                'Criteria must be an array of query fields or a %s',
157
                QueryBuilder::class
158
            ));
159
        }
160
161
        $entityAlias = $this->getClassAlias();
162
        $queryBuilder = $this->createQueryBuilder($entityAlias);
163
164
        /* @var array $criteria */
165
        foreach ($criteria as $field => $value) {
166
            if (is_null($value)) {
167
                $queryBuilder->andWhere(sprintf('%s.%s IS NULL', $entityAlias, $field));
168
            } else {
169
                $parameter = sprintf('%s_%s', $field, substr(sha1($field), 0, 4));
170
171
                $queryBuilder->andWhere(sprintf('%s.%s = :%s', $entityAlias, $field, $parameter));
172
                $queryBuilder->setParameter($parameter, $value);
173
            }
174
        }
175
176
        return $queryBuilder;
177
    }
178
}
179