ComplexSortStrategy   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 94
Duplicated Lines 0 %

Test Coverage

Coverage 85.71%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 36
c 1
b 0
f 0
dl 0
loc 94
ccs 36
cts 42
cp 0.8571
rs 10
wmc 17

5 Methods

Rating   Name   Duplication   Size   Complexity  
A sort() 0 7 2
A __construct() 0 4 2
A createSortTransformFunction() 0 22 3
A sortBy() 0 9 1
B getPropertyExtractor() 0 23 9
1
<?php
2
3
namespace Ninja\Sorter\Strategy;
4
5
use ArrayAccess;
6
use Closure;
7
use Ninja\Sorter\Comparator\ComparatorInterface;
8
use Ninja\Sorter\Comparator\UnicodeCIComparator;
0 ignored issues
show
Bug introduced by
The type Ninja\Sorter\Comparator\UnicodeCIComparator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
10
class ComplexSortStrategy extends AbstractSortStrategy
11
{
12
    /**
13
     * @var array<string|int, mixed>
14
     */
15
    private array $property_map = [];
16
17
    public function __construct(protected ?ComparatorInterface $comparator = null)
18
    {
19 1
        if ($this->comparator === null) {
20
            $this->comparator = new UnicodeCIComparator();
21 1
        }
22 1
    }
23
24
    public function sortBy(mixed $accessor, int $order = null, ComparatorInterface $comparator = null): static
25
    {
26 1
        $this->property_map[] = [
27
            'accessor'   => $accessor,
28 1
            'direction'  => $order      ?? $this->getOrder(),
29 1
            'comparator' => $comparator ?? $this->getComparator(),
30 1
        ];
31 1
32 1
        return $this;
33
    }
34 1
35
    protected function createSortTransformFunction(): Closure
36
    {
37 1
        $propertyMap       = $this->property_map;
38
        $propertyExtractor = $this->getPropertyExtractor();
39 1
        $valueChecker      = $this->getValueChecker();
40 1
41 1
        return static function (mixed $a, mixed $b) use ($propertyMap, $propertyExtractor, $valueChecker) {
42
43 1
            foreach ($propertyMap as $property) {
44
                $valueA = $propertyExtractor($a, $property['accessor']);
45 1
                $valueB = $propertyExtractor($b, $property['accessor']);
46 1
47 1
                $cmp = $property['comparator'];
48
                $valueChecker($valueA, $valueB, $cmp);
49 1
                $result = $cmp->compare($valueA, $valueB);
50 1
51 1
                if ($result !== 0) {
52
                    return $result * $property['direction'];
53 1
                }
54 1
            }
55
56
            return 0;
57
        };
58
    }
59 1
60
    /**
61
     * Get callable used for extracting values from sortable entities (objects, arrays etc.)
62
     * This method extracts value from k, where k is an element of collection(i => k).
63
     * Accessor can be customized to add sorting ability to a complex objects.
64
     *
65
     * @return Closure Takes two arguments, $property and $accessor
66
     */
67
    private function getPropertyExtractor(): Closure
68
    {
69 1
        return static function (mixed $property, mixed $accessor = null): mixed {
70
71 1
            if (is_string($property) || !$accessor) {
72
                return $property;
73 1
            }
74
75
            if ($accessor instanceof Closure) {
76
                return $accessor($property);
77 1
            }
78
79
            if (is_string($accessor)) {
80
                if (is_array($property) || $property instanceof ArrayAccess) {
81 1
                    return $property[$accessor];
82 1
                }
83
84
                if (is_object($property) && property_exists($property, $accessor)) {
85
                    return $property->{$accessor};
86 1
                }
87 1
            }
88
89
            throw new \RuntimeException(sprintf('Unable to resolve property value: %s', gettype($property)));
90
        };
91
    }
92 1
93
    /**
94
     * @param array<string|int, mixed> $collection
95 1
     * @return array<string|int, mixed>
96
     */
97 1
    public function sort(array $collection): array
98
    {
99
        if (empty($this->property_map)) {
100
            throw new \RuntimeException('Missing sort properties - add them using sortBy(...)');
101 1
        }
102
103
        return parent::sort($collection);
104
    }
105
}
106