Test Failed
Push — master ( ce3748...e186d3 )
by Kirill
02:26
created

HigherOrderCollectionProxy   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Importance

Changes 0
Metric Value
wmc 28
lcom 0
cbo 1
dl 0
loc 163
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B __get() 0 26 6
B __call() 0 26 6
A isArrayable() 0 4 2
A hasCallableKey() 0 4 2
A hasProperty() 0 7 3
A hasCallableProperty() 0 4 2
A hasMethod() 0 7 3
A pack() 0 10 3
1
<?php
2
/**
3
 * This file is part of Hydrogen package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace RDS\Hydrogen\HighOrderMessaging;
11
12
use Illuminate\Support\Str;
13
use RDS\Hydrogen\Collection;
14
15
/**
16
 * Class HigherOrderCollectionProxy
17
 */
18
class HigherOrderCollectionProxy
19
{
20
    /**
21
     * This pattern is used to specify the location of the delegate in
22
     * the function arguments in the high-order messaging.
23
     */
24
    public const PATTERN = '_';
25
26
    /**
27
     * @var Collection
28
     */
29
    private $collection;
30
31
    /**
32
     * @var string
33
     */
34
    private $method;
35
36
    /**
37
     * HighOrderCollectionProxy constructor.
38
     * @param Collection $collection
39
     * @param string $method
40
     */
41
    public function __construct(Collection $collection, string $method)
42
    {
43
        $this->collection = $collection;
44
        $this->method = $method;
45
    }
46
47
    /**
48
     * @param string $property
49
     * @return Collection|mixed
50
     */
51
    public function __get(string $property)
52
    {
53
        return $this->collection->{$this->method}(function($item) use ($property) {
54
            if ($this->hasProperty($item, $property)) {
55
                return $item->$property;
56
            }
57
58
            if ($this->isArrayable($item)) {
59
                return $item[$property];
60
            }
61
62
            if ($this->hasMethod($item, $property)) {
63
                return $item->$property();
64
            }
65
66
            if (\function_exists($property)) {
67
                return $property($item);
68
            }
69
70
            $snake = Str::snake($property);
71
72
            if (\function_exists($snake)) {
73
                return $snake($item);
74
            }
75
        });
76
    }
77
78
    /**
79
     * @param string $method
80
     * @param array $arguments
81
     * @return Collection|mixed
82
     */
83
    public function __call(string $method, array $arguments = [])
84
    {
85
        return $this->collection->{$this->method}(function($item) use ($method, $arguments) {
86
            if ($this->hasMethod($item, $method)) {
87
                return $item->$method(...$arguments);
88
            }
89
90
            if ($this->hasCallableProperty($item, $method)) {
91
                return ($item->$method)(...$arguments);
92
            }
93
94
            if ($this->hasCallableKey($item, $method)) {
95
                return $item[$method](...$arguments);
96
            }
97
98
            if (\function_exists($method)) {
99
                return $method(...$this->pack($item, $arguments));
100
            }
101
102
            $snake = Str::snake($method);
103
104
            if (\function_exists(Str::snake($snake))) {
105
                return $snake(...$this->pack($item, $arguments));
106
            }
107
        });
108
    }
109
110
    /**
111
     * @param object $context
112
     * @return bool
113
     */
114
    private function isArrayable($context): bool
115
    {
116
        return \is_array($context) || $context instanceof \ArrayAccess;
117
    }
118
119
    /**
120
     * @param object $context
121
     * @param string $key
122
     * @return bool
123
     */
124
    private function hasCallableKey($context, string $key): bool
125
    {
126
        return $this->isArrayable($context) && \is_callable($context[$key] ?? null);
127
    }
128
129
    /**
130
     * @param object $context
131
     * @param string $property
132
     * @return bool
133
     */
134
    private function hasProperty($context, string $property): bool
135
    {
136
        return \is_object($context) && (
137
            \property_exists($context, $property) ||
138
            \method_exists($context, '__get')
139
        );
140
    }
141
142
    /**
143
     * @param object $context
144
     * @param string $property
145
     * @return bool
146
     */
147
    private function hasCallableProperty($context, string $property): bool
148
    {
149
        return $this->hasProperty($context, $property) && \is_callable($context->$property);
150
    }
151
152
    /**
153
     * @param object $context
154
     * @param string $method
155
     * @return bool
156
     */
157
    private function hasMethod($context, string $method): bool
158
    {
159
        return \is_object($context) && (
160
            \method_exists($context, $method) ||
161
            \method_exists($context, '__call')
162
        );
163
    }
164
165
    /**
166
     * @param object $context
167
     * @param array $parameters
168
     * @return array
169
     */
170
    private function pack($context, array $parameters): array
171
    {
172
        $result = [];
173
174
        foreach ($parameters as $parameter) {
175
            $result[] = $parameter === self::PATTERN ? $context : $parameter;
176
        }
177
178
        return $result;
179
    }
180
}
181