Passed
Push — master ( 23e124...af9f12 )
by Kevin
07:04
created

ORMQueryResult.php$0 ➔ cloneQuery()   A

Complexity

Conditions 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
ccs 5
cts 6
cp 0.8333
crap 2.0185
1
<?php
2
3
namespace Zenstruck\Porpaginas\Doctrine;
4
5
use Doctrine\ORM\Query;
6
use Doctrine\ORM\QueryBuilder;
7
use Doctrine\ORM\Tools\Pagination\Paginator;
8
use Zenstruck\Porpaginas\Callback\CallbackPage;
9
use Zenstruck\Porpaginas\Doctrine\Batch\ORMCountableBatchProcessor;
10
use Zenstruck\Porpaginas\Doctrine\Batch\ORMIterableResultDecorator;
11
use Zenstruck\Porpaginas\Page;
12
use Zenstruck\Porpaginas\Result;
13
14
final class ORMQueryResult implements Result
15
{
16
    private Query $query;
17
    private bool $fetchCollection;
18
    private ?bool $useOutputWalkers;
19
    private ?int $count = null;
20
21
    /**
22
     * @param Query|QueryBuilder $query
23
     */
24
    public function __construct($query, bool $fetchCollection = true, ?bool $useOutputWalkers = null)
25
    {
26
        if ($query instanceof QueryBuilder) {
27
            $query = $query->getQuery();
28
        }
29
30
        $this->query = $query;
31
        $this->fetchCollection = $fetchCollection;
32
        $this->useOutputWalkers = $useOutputWalkers;
33
    }
34
35
    public function take(int $offset, int $limit): Page
36
    {
37
        return new CallbackPage(
38
            function($offset, $limit) {
39
                return \iterator_to_array($this->paginatorFor(
40
                    $this->cloneQuery()->setFirstResult($offset)->setMaxResults($limit)
41
                ));
42
            },
43
            [$this, 'count'],
44
            $offset,
45
            $limit
46
        );
47
    }
48
49
    public function count(): int
50
    {
51
        if (null !== $this->count) {
52
            return $this->count;
53
        }
54
55
        return $this->count = \count($this->paginatorFor($this->cloneQuery()));
56
    }
57
58
    public function getIterator(): \Traversable
59
    {
60
        return $this->batchIterator();
61
    }
62
63
    public function batchIterator(int $chunkSize = 100): \Traversable
64
    {
65
        $iteration = 0;
66
67
        foreach (new ORMIterableResultDecorator($this->cloneQuery()->iterate()) as $key => $value) {
68
            yield $key => $value;
69
70
            if (++$iteration % $chunkSize) {
71
                continue;
72
            }
73
74
            $this->query->getEntityManager()->clear();
75
        }
76
77
        $this->query->getEntityManager()->clear();
78
    }
79
80 8
    public function batchProcessor(int $chunkSize = 100): ORMCountableBatchProcessor
81
    {
82
        return new ORMCountableBatchProcessor(
83
            new class($this->cloneQuery(), $this) implements \IteratorAggregate, \Countable {
84
                private Query $query;
85
                private Result $result;
86
87
                public function __construct(Query $query, Result $result)
88
                {
89 8
                    $this->query = $query;
90 8
                    $this->result = $result;
91 8
                }
92
93
                public function getIterator(): \Traversable
94
                {
95 8
                    return new ORMIterableResultDecorator($this->query->iterate());
96
                }
97
98
                public function count(): int
99
                {
100 8
                    return $this->result->count();
101
                }
102
            },
103 8
            $this->query->getEntityManager(),
104
            $chunkSize
105
        );
106
    }
107
108 38
    private function paginatorFor(Query $query): Paginator
109
    {
110 38
        return (new Paginator($query, $this->fetchCollection))->setUseOutputWalkers($this->useOutputWalkers);
111
    }
112
113 45
    private function cloneQuery(): Query
114
    {
115 45
        $query = clone $this->query;
116 45
        $query->setParameters($this->query->getParameters());
117
118 45
        foreach ($this->query->getHints() as $name => $value) {
119
            $query->setHint($name, $value);
120
        }
121
122 45
        return $query;
123
    }
124
}
125