Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / orm / lib / Doctrine / ORM / Tools / Pagination / Paginator.php
1 <?php
2 /*
3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * This software consists of voluntary contributions made by many individuals
16  * and is licensed under the MIT license. For more information, see
17  * <http://www.doctrine-project.org>.
18  */
19
20 namespace Doctrine\ORM\Tools\Pagination;
21
22 use Doctrine\ORM\QueryBuilder,
23     Doctrine\ORM\Query,
24     Doctrine\ORM\Query\ResultSetMapping,
25     Doctrine\ORM\NoResultException;
26
27 /**
28  * Paginator
29  *
30  * The paginator can handle various complex scenarios with DQL.
31  *
32  * @author Pablo Díez <pablodip@gmail.com>
33  * @author Benjamin Eberlei <kontakt@beberlei.de>
34  * @license New BSD
35  */
36 class Paginator implements \Countable, \IteratorAggregate
37 {
38     /**
39      * @var Query
40      */
41     private $query;
42
43     /**
44      * @var bool
45      */
46     private $fetchJoinCollection;
47
48     /**
49      * @var bool|null
50      */
51     private $useOutputWalkers;
52
53     /**
54      * @var int
55      */
56     private $count;
57
58     /**
59      * Constructor.
60      *
61      * @param Query|QueryBuilder $query A Doctrine ORM query or query builder.
62      * @param Boolean $fetchJoinCollection Whether the query joins a collection (true by default).
63      */
64     public function __construct($query, $fetchJoinCollection = true)
65     {
66         if ($query instanceof QueryBuilder) {
67             $query = $query->getQuery();
68         }
69
70         $this->query = $query;
71         $this->fetchJoinCollection = (Boolean) $fetchJoinCollection;
72     }
73
74     /**
75      * Returns the query
76      *
77      * @return Query
78      */
79     public function getQuery()
80     {
81         return $this->query;
82     }
83
84     /**
85      * Returns whether the query joins a collection.
86      *
87      * @return Boolean Whether the query joins a collection.
88      */
89     public function getFetchJoinCollection()
90     {
91         return $this->fetchJoinCollection;
92     }
93
94     /**
95      * Returns whether the paginator will use an output walker
96      *
97      * @return bool|null
98      */
99     public function getUseOutputWalkers()
100     {
101         return $this->useOutputWalkers;
102     }
103
104     /**
105      * Set whether the paginator will use an output walker
106      *
107      * @param bool|null $useOutputWalkers
108      * @return $this
109      */
110     public function setUseOutputWalkers($useOutputWalkers)
111     {
112         $this->useOutputWalkers = $useOutputWalkers;
113         return $this;
114     }
115
116     /**
117      * {@inheritdoc}
118      */
119     public function count()
120     {
121         if ($this->count === null) {
122             /* @var $countQuery Query */
123             $countQuery = $this->cloneQuery($this->query);
124
125             if ( ! $countQuery->getHint(CountWalker::HINT_DISTINCT)) {
126                 $countQuery->setHint(CountWalker::HINT_DISTINCT, true);
127             }
128
129             if ($this->useOutputWalker($countQuery)) {
130                 $platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win
131
132                 $rsm = new ResultSetMapping();
133                 $rsm->addScalarResult($platform->getSQLResultCasing('dctrn_count'), 'count');
134
135                 $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker');
136                 $countQuery->setResultSetMapping($rsm);
137             } else {
138                 $countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
139             }
140
141             $countQuery->setFirstResult(null)->setMaxResults(null);
142
143             try {
144                 $data =  $countQuery->getScalarResult();
145                 $data = array_map('current', $data);
146                 $this->count = array_sum($data);
147             } catch(NoResultException $e) {
148                 $this->count = 0;
149             }
150         }
151         return $this->count;
152     }
153
154     /**
155      * {@inheritdoc}
156      */
157     public function getIterator()
158     {
159         $offset = $this->query->getFirstResult();
160         $length = $this->query->getMaxResults();
161
162         if ($this->fetchJoinCollection) {
163             $subQuery = $this->cloneQuery($this->query);
164
165             if ($this->useOutputWalker($subQuery)) {
166                 $subQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
167             } else {
168                 $subQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'));
169             }
170
171             $subQuery->setFirstResult($offset)->setMaxResults($length);
172
173             $ids = array_map('current', $subQuery->getScalarResult());
174
175             $whereInQuery = $this->cloneQuery($this->query);
176             // don't do this for an empty id array
177             if (count($ids) == 0) {
178                 return new \ArrayIterator(array());
179             }
180
181             $namespace = WhereInWalker::PAGINATOR_ID_ALIAS;
182
183             $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
184             $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, count($ids));
185             $whereInQuery->setFirstResult(null)->setMaxResults(null);
186             foreach ($ids as $i => $id) {
187                 $i++;
188                 $whereInQuery->setParameter("{$namespace}_{$i}", $id);
189             }
190
191             $result = $whereInQuery->getResult($this->query->getHydrationMode());
192         } else {
193             $result = $this->cloneQuery($this->query)
194                 ->setMaxResults($length)
195                 ->setFirstResult($offset)
196                 ->getResult($this->query->getHydrationMode())
197             ;
198         }
199         return new \ArrayIterator($result);
200     }
201
202     /**
203      * Clones a query.
204      *
205      * @param Query $query The query.
206      *
207      * @return Query The cloned query.
208      */
209     private function cloneQuery(Query $query)
210     {
211         /* @var $cloneQuery Query */
212         $cloneQuery = clone $query;
213
214         $cloneQuery->setParameters(clone $query->getParameters());
215
216         foreach ($query->getHints() as $name => $value) {
217             $cloneQuery->setHint($name, $value);
218         }
219
220         return $cloneQuery;
221     }
222
223     /**
224      * Determine whether to use an output walker for the query
225      *
226      * @param Query $query The query.
227      *
228      * @return bool
229      */
230     private function useOutputWalker(Query $query)
231     {
232         if ($this->useOutputWalkers === null) {
233             return (Boolean) $query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER) == false;
234         }
235
236         return $this->useOutputWalkers;
237     }
238 }
239