Passed
Pull Request — master (#29)
by Sébastien
08:57
created

KeyWalkStrategy::next()   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5.0144

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
dl 0
loc 24
ccs 11
cts 12
cp 0.9167
rs 9.5555
c 1
b 0
f 0
cc 5
nc 12
nop 1
crap 5.0144
1
<?php
2
3
namespace Bdf\Prime\Query\Pagination\WalkStrategy;
4
5
use Bdf\Prime\Collection\CollectionInterface;
6
use Bdf\Prime\Connection\ConnectionInterface;
7
use Bdf\Prime\Query\Contract\Limitable;
8
use Bdf\Prime\Query\Contract\Orderable;
9
use Bdf\Prime\Query\Contract\ReadOperation;
10
use Bdf\Prime\Query\Contract\Whereable;
11
use Bdf\Prime\Query\ReadCommandInterface;
12
use InvalidArgumentException;
13
14
/**
15
 * Walk strategy using a primary key (or any unique key) as cursor
16
 * This strategy supports deleting entities during the walk, but the entity must contains a single primary key, and the query must be ordered by this key
17
 * Any sort on other attribute are not supported
18
 *
19
 * @template E as object
20
 * @implements WalkStrategyInterface<E>
21
 */
22
final class KeyWalkStrategy implements WalkStrategyInterface
23
{
24
    /**
25
     * @var KeyInterface<E>
0 ignored issues
show
introduced by
Expected "KeyInterfaceE" but found "KeyInterface<E>" for @var tag in member variable comment
Loading history...
26
     */
27
    private $key;
28
29
    /**
30
     * PrimaryKeyWalkStrategy constructor.
31
     *
32
     * @param KeyInterface<E> $key
0 ignored issues
show
introduced by
Expected "KeyInterfaceE" but found "KeyInterface<E>" for parameter type
Loading history...
33
     */
34 16
    public function __construct(KeyInterface $key)
35
    {
36 16
        $this->key = $key;
37 16
    }
38
39
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $query should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $chunkSize should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $startPage should have a doc-comment as per coding-style.
Loading history...
40
     * {@inheritdoc}
41
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @throws tag in function comment
Loading history...
42 13
    public function initialize(ReadCommandInterface $query, int $chunkSize, int $startPage): WalkCursor
43
    {
44 13
        if (!self::supports($query, $startPage, $this->key->name())) {
45 3
            throw new InvalidArgumentException('KeyWalkStrategy is not supported by this query');
46
        }
47
48
        /** @var Limitable&Orderable&ReadCommandInterface<ConnectionInterface, E> $query */
0 ignored issues
show
Coding Style introduced by
Block comments must be started with /*
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
49 10
        $query = clone $query;
50
51 10
        if (!isset($query->getOrders()[$this->key->name()])) {
52 10
            $query->order($this->key->name(), Orderable::ORDER_ASC);
53
        }
54
55 10
        $query->limit($chunkSize);
56
57
        /** @var WalkCursor<E> */
0 ignored issues
show
Coding Style introduced by
Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead
Loading history...
Coding Style introduced by
Block comments must be started with /*
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
58 10
        return new WalkCursor($query);
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    #[ReadOperation]
65 10
    public function next(WalkCursor $cursor): WalkCursor
66
    {
67 10
        $cursor = clone $cursor;
68
69 10
        if ($cursor->entities) {
70 8
            $cursor->cursor = $this->key->get(end($cursor->entities));
71
        }
72
73 10
        if ($cursor->cursor !== null) {
74
            /** @var ReadCommandInterface<ConnectionInterface, E>&Orderable&Whereable $query */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Block comments must be started with /*
Loading history...
Coding Style introduced by
Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead
Loading history...
75 8
            $query = $cursor->query;
76 8
            $operator = $query->getOrders()[$this->key->name()] === Orderable::ORDER_ASC ? '>' : '<';
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
Bug introduced by
The method getOrders() does not exist on Bdf\Prime\Query\ReadCommandInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Bdf\Prime\Query\Contract...\KeyValueQueryInterface or Bdf\Prime\Query\QueryInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

76
            $operator = $query->/** @scrutinizer ignore-call */ getOrders()[$this->key->name()] === Orderable::ORDER_ASC ? '>' : '<';
Loading history...
Coding Style introduced by
The value of a comparison must not be assigned to a variable
Loading history...
77
78 8
            $query->where($this->key->name(), $operator, $cursor->cursor);
0 ignored issues
show
Bug introduced by
The method where() does not exist on Bdf\Prime\Query\ReadCommandInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Query\ReadCommandInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
            $query->/** @scrutinizer ignore-call */ 
79
                    where($this->key->name(), $operator, $cursor->cursor);
Loading history...
79
        }
80
81 10
        $cursor->entities = $cursor->query->all();
0 ignored issues
show
Documentation Bug introduced by
It seems like $cursor->query->all() of type Bdf\Prime\Query\R[]&Bdf\...ion\CollectionInterface is incompatible with the declared type Bdf\Prime\Query\Pagination\WalkStrategy\R[]|null of property $entities.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
82
83 10
        if ($cursor->entities instanceof CollectionInterface) {
84
            $cursor->entities = $cursor->entities->all();
85
        }
86
87 10
        return $cursor;
88
    }
89
90
    /**
91
     * Check if the strategy supports the given parameters
92
     *
93
     * @param ReadCommandInterface $query The query
94
     * @param int|null $startPage The start page
0 ignored issues
show
Coding Style introduced by
Expected "integer|null" but found "int|null" for parameter type
Loading history...
95
     * @param string $key The cursor key
96
     *
97
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
98
     *
99
     * @psalm-assert-if-true Orderable&Limitable&Whereable $query
100
     */
101 16
    public static function supports(ReadCommandInterface $query, ?int $startPage, string $key): bool
102
    {
103 16
        if ($startPage !== null && $startPage !== 1) {
104 3
            return false;
105
        }
106
107 14
        if (!($query instanceof Orderable && $query instanceof Limitable && $query instanceof Whereable)) {
108 2
            return false;
109
        }
110
111 13
        $orders = $query->getOrders();
112
113 13
        return empty($orders) || (count($orders) === 1 && isset($orders[$key]));
0 ignored issues
show
Coding Style introduced by
Boolean operators are not allowed outside of control structure conditions
Loading history...
114
    }
115
}
116