Completed
Pull Request — master (#239)
by
unknown
09:24
created

ConcatenationAdapter::refreshAdaptersNbResults()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 4
nop 0
crap 3
1
<?php
2
3
/*
4
 * This file is part of the Pagerfanta package.
5
 *
6
 * (c) Pablo Díez <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Pagerfanta\Adapter;
13
14
use Pagerfanta\Exception\InvalidArgumentException;
15
16
/**
17
 * Adapter that concatenates other adapters.
18
 *
19
 * @author Surgie Finesse <[email protected]>
20
 */
21
class ConcatenationAdapter implements AdapterInterface
22
{
23
    /**
24
     * @var AdapterInterface[] List of adapters
25
     */
26
    protected $adapters;
27
28
    /**
29
     * @var int[]|null Cache of the numbers of results of the adapters. The indexes correspond the indexes of the
30
     * `adapters` property.
31
     */
32
    protected $adaptersNbResultsCache;
33
34
    /**
35
     * @param AdapterInterface[] $adapters
36
     * @throws InvalidArgumentException
37
     */
38 3
    public function __construct(array $adapters)
39
    {
40 3
        foreach ($adapters as $index => $adapter) {
41 3
            if (!($adapter instanceof AdapterInterface)) {
42 1
                throw new InvalidArgumentException(
43 1
                    'Argument $adapters['.$index.'] expected to be a \Pagerfanta\Adapter\AdapterInterface instance'
44 1
                        . ', a '.(is_object($adapter) ? get_class($adapter).' instance' : gettype($adapter)).' given'
45 1
                );
46
            }
47 3
        }
48
49 3
        $this->adapters = $adapters;
50 3
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55 1
    public function getNbResults()
56
    {
57 1
        if (!isset($this->adaptersNbResultsCache)) {
58 1
            $this->refreshAdaptersNbResults();
59 1
        }
60
61 1
        return array_sum($this->adaptersNbResultsCache);
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67 1
    public function getSlice($offset, $length)
68
    {
69 1
        if (!isset($this->adaptersNbResultsCache)) {
70 1
            $this->refreshAdaptersNbResults();
71 1
        }
72
73 1
        $slice = array();
74 1
        $previousAdaptersNbResultsSum = 0;
75 1
        $searchFirstIndex = $offset;
76 1
        $searchLastIndex  = $offset + $length - 1;
77
78 1
        foreach ($this->adapters as $index => $adapter) {
79 1
            $adapterNbResults  = $this->adaptersNbResultsCache[$index];
80 1
            $adapterFirstIndex = $previousAdaptersNbResultsSum;
81 1
            $adapterLastIndex  = $adapterFirstIndex + $adapterNbResults - 1;
82
83 1
            $previousAdaptersNbResultsSum += $adapterNbResults;
84
85
            // The adapter is below the requested slice range — skip it
86 1
            if ($adapterLastIndex < $searchFirstIndex) {
87 1
                continue;
88
            }
89
90
            // The adapter is above the requested slice range — finish the gathering
91 1
            if ($adapterFirstIndex > $searchLastIndex) {
92 1
                break;
93
            }
94
95
            // Else the adapter range definitely intersects with the requested range
96 1
            $fetchOffset = $searchFirstIndex - $adapterFirstIndex;
97 1
            $fetchLength = $length;
98
99
            // The requested range peeps above the bottom edge of the adapter range
100 1
            if ($fetchOffset < 0) {
101 1
                $fetchLength += $fetchOffset;
102 1
                $fetchOffset = 0;
103 1
            }
104
105
            // The requested range peeps above the top edge of the adapter range
106 1
            if ($fetchOffset + $fetchLength > $adapterNbResults) {
107 1
                $fetchLength = $adapterNbResults - $fetchOffset;
108 1
            }
109
110
            // Getting the subslice from the adapter and adding it to the result slice
111 1
            $fetchSlice = $adapter->getSlice($fetchOffset, $fetchLength);
112 1
            $slice = array_merge($slice, $fetchSlice);
113 1
        }
114
115 1
        return $slice;
116
    }
117
118
    /**
119
     * Refreshes the cache of the numbers of results of the adapters.
120
     */
121 2
    protected function refreshAdaptersNbResults()
122
    {
123 2
        if (!isset($this->adaptersNbResultsCache)) {
124 2
            $this->adaptersNbResultsCache = array();
125 2
        }
126
127 2
        foreach ($this->adapters as $index => $adapter) {
128 2
            $this->adaptersNbResultsCache[$index] = $adapter->getNbResults();
129 2
        }
130 2
    }
131
}
132