Completed
Push — develop ( fae9ec...31c95d )
by Neomerx
03:53
created

EventSettings::getSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
crap 1
1
<?php namespace Limoncello\Events\Package;
2
3
/**
4
 * Copyright 2015-2017 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use Generator;
20
use Limoncello\Contracts\Settings\SettingsInterface;
21
use Limoncello\Core\Reflection\ClassIsTrait;
22
use Limoncello\Events\Contracts\EventHandlerInterface;
23
use Limoncello\Events\Contracts\EventInterface;
24
use Limoncello\Events\SimpleEventEmitter;
25
use ReflectionClass;
26
use ReflectionMethod;
27
28
/**
29
 * @package Limoncello\Events
30
 */
31
abstract class EventSettings implements SettingsInterface
32
{
33
    use ClassIsTrait;
34
35
    /** Settings key */
36
    const KEY_EVENTS_FOLDER = 0;
37
38
    /** Settings key */
39
    const KEY_EVENTS_FILE_MASK = self::KEY_EVENTS_FOLDER + 1;
40
41
    /** Settings key */
42
    const KEY_SUBSCRIBERS_FOLDER = self::KEY_EVENTS_FILE_MASK + 1;
43
44
    /** Settings key */
45
    const KEY_SUBSCRIBERS_FILE_MASK = self::KEY_SUBSCRIBERS_FOLDER + 1;
46
47
    /** Settings key */
48
    const KEY_CACHED_DATA = self::KEY_SUBSCRIBERS_FILE_MASK + 1;
49
50
    /** Settings key */
51
    const KEY_LAST = self::KEY_CACHED_DATA;
52
53
    /**
54
     * @return array
55
     */
56 2
    final public function get(): array
57
    {
58 2
        $defaults = $this->getSettings();
59
60 2
        $eventsFolder = $defaults[static::KEY_EVENTS_FOLDER] ?? null;
61 2
        assert(
62 2
            $eventsFolder !== null && empty(glob($eventsFolder)) === false,
63 2
            "Invalid Events folder `$eventsFolder`."
64
        );
65
66 2
        $eventsFileMask = $defaults[static::KEY_EVENTS_FILE_MASK] ?? null;
67 2
        assert(empty($eventsFileMask) === false, "Invalid Events file mask `$eventsFileMask`.");
68
69 2
        $subscribersFolder = $defaults[static::KEY_SUBSCRIBERS_FOLDER] ?? null;
70 2
        assert(
71 2
            $subscribersFolder !== null && empty(glob($subscribersFolder)) === false,
72 2
            "Invalid Subscribers folder `$subscribersFolder`."
73
        );
74
75 2
        $subscribersFileMask = $defaults[static::KEY_SUBSCRIBERS_FILE_MASK] ?? null;
76 2
        assert(empty($subscribersFileMask) === false, "Invalid Subscribers file mask `$subscribersFileMask`.");
77
78 2
        $eventsPath      = $eventsFolder . DIRECTORY_SEPARATOR . $eventsFileMask;
79 2
        $subscribersPath = $subscribersFolder . DIRECTORY_SEPARATOR . $subscribersFileMask;
80
81 2
        $emitter        = new SimpleEventEmitter();
82 2
        $eventClasses   = iterator_to_array(
83 2
            $this->selectClasses($eventsPath, EventInterface::class)
84
        );
85 2
        $handlerClasses = iterator_to_array(
86 2
            $this->selectClasses($subscribersPath, EventHandlerInterface::class)
87
        );
88 2
        foreach ($this->getEventSubscribers($eventClasses, $handlerClasses) as $eventClass => $subscriber) {
89 2
            $emitter->subscribe($eventClass, $subscriber);
0 ignored issues
show
Documentation introduced by
$subscriber is of type *, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
90
        }
91
92 2
        $cacheData = $emitter->getStaticSubscribers();
93
94 2
        return $defaults + [static::KEY_CACHED_DATA => $cacheData];
95
    }
96
97
    /**
98
     * @return array
99
     */
100 2
    protected function getSettings(): array
101
    {
102
        return [
103 2
            static::KEY_EVENTS_FILE_MASK      => '*.php',
104 2
            static::KEY_SUBSCRIBERS_FILE_MASK => '*.php',
105
        ];
106
    }
107
108
    /**
109
     * @param array $eventClasses
110
     * @param array $handlerClasses
111
     *
112
     * @return Generator
113
     */
114 2
    private function getEventSubscribers(array $eventClasses, array $handlerClasses): Generator
115
    {
116 2
        foreach ($handlerClasses as $handlerClass) {
117 2
            foreach ($this->selectEvenHandlers($handlerClass) as $eventClass => $subscriber) {
118 2
                foreach ($this->getChildEvents($eventClass, $eventClasses) as $childEventClass) {
119 2
                    yield $childEventClass => $subscriber;
120
                }
121
            }
122
        }
123
    }
124
125
    /**
126
     * @param string $handlerClass
127
     *
128
     * @return Generator
129
     */
130 2
    private function selectEvenHandlers(string $handlerClass): Generator
131
    {
132 2
        $reflection = new ReflectionClass($handlerClass);
133 2
        foreach ($reflection->getMethods(ReflectionMethod::IS_STATIC | ReflectionMethod::IS_PUBLIC) as $method) {
134 2
            if ($this->isEventHandlerMethod($method) === true) {
135 2
                $eventClass = $method->getParameters()[0]->getClass()->getName();
136 2
                $subscriber = [$handlerClass, $method->getName()];
137 2
                yield $eventClass => $subscriber;
138
            }
139
        }
140
    }
141
142
    /**
143
     * @param string $eventClass
144
     * @param array  $eventClasses
145
     *
146
     * @return Generator
147
     */
148 2
    private function getChildEvents(string $eventClass, array $eventClasses): Generator
149
    {
150 2
        $reflection = new ReflectionClass($eventClass);
151 2
        foreach ($eventClasses as $curEventClass) {
152 2
            $curReflection = new ReflectionClass($curEventClass);
153 2
            if ($curReflection->isAbstract() === false) {
154 2
                if ($eventClass === $curEventClass ||
155 2
                    $curReflection->isSubclassOf($eventClass) === true ||
156 2
                    ($reflection->isInterface() === true && $curReflection->implementsInterface($eventClass))
157
                ) {
158 2
                    yield $curEventClass;
159
                }
160
            }
161
        }
162
    }
163
164
    /**
165
     * @param ReflectionMethod $method
166
     *
167
     * @return bool
168
     */
169 2
    private function isEventHandlerMethod(ReflectionMethod $method): bool
170
    {
171
        $result =
172 2
            $method->isPublic() === true &&
173 2
            $method->isStatic() === true &&
174 2
            count($params = $method->getParameters()) === 1 &&
175 2
            $params[0]->getClass()->implementsInterface(EventInterface::class) === true;
176
177 2
        return $result;
178
    }
179
}
180