ORMQueryResult   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 111
Duplicated Lines 0 %

Test Coverage

Coverage 93.33%

Importance

Changes 5
Bugs 0 Features 2
Metric Value
eloc 45
dl 0
loc 111
ccs 14
cts 15
cp 0.9333
rs 10
c 5
b 0
f 2
wmc 7

14 Methods

Rating   Name   Duplication   Size   Complexity  
A hp$0 ➔ count() 0 3 1
A take() 0 11 1
cloneQuery() 0 10 ?
A hp$0 ➔ __construct() 0 4 1
A __construct() 0 9 2
A hp$0 ➔ paginatorFor() 0 3 1
paginatorFor() 0 3 ?
A batchIterator() 0 15 3
A hp$0 ➔ batchProcessor() 0 25 1
A hp$0 ➔ getIterator() 0 3 1
A count() 0 7 2
batchProcessor() 0 25 ?
A getIterator() 0 3 1
A hp$0 ➔ cloneQuery() 0 10 2
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