Passed
Push — master ( 34488c...4ee1ca )
by Maxim
02:53 queued 11s
created

Group::count()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Anton Lytkin <[email protected]>
4
 */
5
6
namespace WS\Utils\Collections\Functions\Group;
7
8
use WS\Utils\Collections\Collection;
9
use WS\Utils\Collections\CollectionFactory;
10
use WS\Utils\Collections\Functions\ObjectFunctions;
11
12
class Group
13
{
14
15
    private $key;
16
    private $aggregators;
17
18 7
    public function __construct(string $key)
19
    {
20 7
        $this->key = $key;
21 7
    }
22
23 7
    public function __invoke(Collection $collection): array
24
    {
25 7
        $groupedResult = $this->group($collection);
26 7
        if (!$this->aggregators) {
27 5
            return $groupedResult;
28
        }
29 2
        return $this->applyAggregators($groupedResult);
30
    }
31
32 7
    private function group(Collection $collection): array
33
    {
34 7
        $result = [];
35 7
        foreach ($collection as $element) {
36 7
            if (!$groupKey = ObjectFunctions::getPropertyValue($element, $this->key)) {
37 1
                continue;
38
            }
39 7
            if (!isset($result[$groupKey])) {
40 7
                $result[$groupKey] = CollectionFactory::empty();
41
            }
42 7
            $result[$groupKey]->add($element);
43
        }
44 7
        return $result;
45
    }
46
47 2
    private function applyAggregators(array $groupedResult): array
48
    {
49 2
        $result = [];
50 2
        foreach ($groupedResult as $groupKey => $items) {
51 2
            foreach ($this->aggregators as $item) {
52 2
                [$destKey, $aggregator] = $item;
53 2
                $result[$groupKey][$destKey] = $aggregator($items);
54
            }
55
        }
56 2
        return $result;
57
    }
58
59
    /**
60
     * Create new instance of Group and use $key as group key
61
     * @param string $key
62
     * @return static
63
     */
64 7
    public static function by(string $key): self
65
    {
66 7
        return new self($key);
67
    }
68
69
    /**
70
     * Will calculate sum of items based on $sourceKey and put it to $destKey
71
     * @param string $sourceKey
72
     * @param string|null $destKey
73
     * @return $this
74
     */
75 2
    public function sum(string $sourceKey, string $destKey = null): self
76
    {
77 2
        return $this->addAggregator($destKey ?? $sourceKey, new Aggregator\Sum($sourceKey));
78
    }
79
80
    /**
81
     * Will calculate minimum value of items based on $sourceKey and put it to $destKey
82
     * @param string $sourceKey
83
     * @param string|null $destKey
84
     * @return $this
85
     */
86 2
    public function min(string $sourceKey, string $destKey = null): self
87
    {
88 2
        return $this->addAggregator($destKey ?? $sourceKey, new Aggregator\Min($sourceKey));
89
    }
90
91
    /**
92
     * Will calculate maximum value of items based on $sourceKey and put it to $destKey
93
     * @param string $sourceKey
94
     * @param string|null $destKey
95
     * @return $this
96
     */
97 2
    public function max(string $sourceKey, string $destKey = null): self
98
    {
99 2
        return $this->addAggregator($destKey ?? $sourceKey, new Aggregator\Max($sourceKey));
100
    }
101
102
    /**
103
     * Will calculate average value of items based on $sourceKey and put it to $destKey
104
     * @param string $sourceKey
105
     * @param string|null $destKey
106
     * @return $this
107
     */
108 2
    public function avg(string $sourceKey, string $destKey = null): self
109
    {
110 2
        return $this->addAggregator($destKey ?? $sourceKey, new Aggregator\Avg($sourceKey));
111
    }
112
113
    /**
114
     * Will find unique values of items based on $sourceKey and put it to $destKey
115
     * @param string $sourceKey
116
     * @param string|null $destKey
117
     * @return $this
118
     */
119 2
    public function addToSet(string $sourceKey, string $destKey = null): self
120
    {
121 2
        return $this->addAggregator($destKey ?? $sourceKey, new Aggregator\AddToSet($sourceKey));
122
    }
123
124
    /**
125
     * Will return first value of items based on $sourceKey and put it to $destKey
126
     * @param string $sourceKey
127
     * @param string|null $destKey
128
     * @return $this
129
     */
130 2
    public function first(string $sourceKey, string $destKey = null): self
131
    {
132 2
        return $this->addAggregator($destKey ?? $sourceKey, new Aggregator\First($sourceKey));
133
    }
134
135
    /**
136
     * Will return last value of items based on $sourceKey and put it to $destKey
137
     * @param string $sourceKey
138
     * @param string|null $destKey
139
     * @return $this
140
     */
141 2
    public function last(string $sourceKey, string $destKey = null): self
142
    {
143 2
        return $this->addAggregator($destKey ?? $sourceKey, new Aggregator\Last($sourceKey));
144
    }
145
146
    /**
147
     * Will calculate count of items in group and put it to $destKey
148
     * @param string $destKey
149
     * @return $this
150
     */
151 2
    public function count(string $destKey): self
152
    {
153 2
        return $this->addAggregator($destKey, new Aggregator\Count());
154
    }
155
156
    /**
157
     * Add custom $aggregator with interface Aggregator\Aggregator|<Fn($c: Collection)>
158
     * @param string $destKey
159
     * @param callable $aggregator
160
     * @return $this
161
     */
162 2
    public function addAggregator(string $destKey, callable $aggregator): self
163
    {
164 2
        $this->aggregators[] = [$destKey, $aggregator];
165 2
        return $this;
166
    }
167
168
}
169