Passed
Push — master ( ed2761...02fcf9 )
by Jonathan
02:28
created

Sorter::__construct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\SkeletonMapper\DataSource;
6
7
use InvalidArgumentException;
8
use function count;
9
use function is_string;
10
use function sprintf;
11
use function strtolower;
12
13
class Sorter
14
{
15
    private const ORDER_ASC  = 'asc';
16
    private const ORDER_DESC = 'desc';
17
18
    /** @var int */
19
    private $level = 0;
20
21
    /** @var string[] */
22
    private $fields;
23
24
    /** @var int[] */
25
    private $orders;
26
27
    /**
28
     * @param string[] $orderBy
29
     */
30 9
    public function __construct(array $orderBy)
31
    {
32 9
        if ($orderBy === []) {
33 1
            throw new InvalidArgumentException('The Sorter class does not accept an empty $orderBy');
34
        }
35
36 8
        foreach ($orderBy as $field => $order) {
37 8
            $this->fields[] = $field;
38 8
            $this->orders[] = $this->getOrder($order);
39
        }
40 7
    }
41
42
    /**
43
     * @param mixed[] $a
44
     * @param mixed[] $b
45
     */
46 7
    public function __invoke(array $a, array $b) : int
47
    {
48 7
        $returnVal        = 0;
49 7
        $comparisonField  = $this->fields[$this->level];
50 7
        $order            = $this->orders[$this->level];
51 7
        $aComparisonField = $this->getComparisonField($a, $comparisonField);
52 6
        $bComparisonField = $this->getComparisonField($b, $comparisonField);
53
54 6
        $comparisonResult = $aComparisonField <=> $bComparisonField;
55
56 6
        if ($comparisonResult !== 0) {
57 6
            $returnVal = $comparisonResult;
58
        } else {
59 3
            if ($this->level < count($this->fields) - 1) {
60 3
                $this->level++;
61
62 3
                return $this->__invoke($a, $b);
63
            }
64
        }
65
66 6
        $returnVal *= $order;
67
68 6
        $this->level = 0;
69
70 6
        return $returnVal;
71
    }
72
73 8
    private function getOrder(string $order) : int
74
    {
75 8
        $lowercaseOrder = strtolower($order);
76
77 8
        if ($lowercaseOrder === self::ORDER_ASC) {
78 4
            return 1;
79
        }
80
81 5
        if ($lowercaseOrder === self::ORDER_DESC) {
82 4
            return -1;
83
        }
84
85 1
        throw new InvalidArgumentException(sprintf(
86 1
            '$order value of %s is not accepted. Only a value of asc or desc is allowed.',
87 1
            $order
88
        ));
89
    }
90
91
    /**
92
     * @param mixed[] $item
93
     *
94
     * @return mixed
95
     */
96 7
    private function getComparisonField(array $item, string $field)
97
    {
98 7
        if (! isset($item[$field])) {
99 1
            throw new InvalidArgumentException(sprintf('Unable to find comparison field %s', $field));
100
        }
101
102 6
        $value = $item[$field];
103
104 6
        return is_string($value) ? strtolower($value) : $value;
105
    }
106
}
107