ORMQueryResult.php$0 ➔ __construct()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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