Completed
Push — master ( c5da41...e1d486 )
by Pieter
22s queued 14s
created

PluginContainer::getPlugin()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 4
eloc 8
c 1
b 0
f 1
nc 5
nop 1
dl 0
loc 13
rs 10
1
<?php
2
3
namespace W2w\Lib\Apie\Core;
4
5
use Generator;
6
use Throwable;
7
use W2w\Lib\Apie\Apie;
8
use W2w\Lib\Apie\Exceptions\BadConfigurationException;
9
use W2w\Lib\Apie\Exceptions\NotAnApiePluginException;
10
11
/**
12
 * Helper method to get all plugins with certain properties.
13
 *
14
 * @internal
15
 */
16
final class PluginContainer
17
{
18
    private $plugins;
19
20
    private $mapping = [];
21
22
    public function __construct(array $plugins)
23
    {
24
        foreach ($plugins as $plugin) {
25
            if (!is_object($plugin)) {
26
                throw new NotAnApiePluginException($plugin);
27
            }
28
            $interfaces = class_implements($plugin);
29
            foreach ($interfaces as $interface) {
30
                if (strpos($interface, 'W2w\Lib\Apie\PluginInterfaces') === 0) {
31
                    continue(2);
32
                }
33
            }
34
            throw new NotAnApiePluginException($plugin);
35
        }
36
        $this->plugins = $plugins;
37
    }
38
39
    /**
40
     * Returns all plugins with a specific interface.
41
     *
42
     * @param string $interface
43
     * @return array
44
     */
45
    public function getPluginsWithInterface(string $interface): array
46
    {
47
        if (!isset($this->mapping[$interface])) {
48
            $res = [];
49
            foreach ($this->plugins as $plugin) {
50
                if ($plugin instanceof $interface) {
51
                    $res[] = $plugin;
52
                }
53
            }
54
            $this->mapping[$interface] = $res;
55
        }
56
        return $this->mapping[$interface];
57
    }
58
59
    /**
60
     * Returns plugin instance.
61
     *
62
     * @param string $pluginClass
63
     * @return object
64
     */
65
    public function getPlugin(string $pluginClass): object
66
    {
67
        $last = null;
68
        foreach ($this->plugins as $plugin) {
69
            if ($plugin instanceof $pluginClass) {
70
                return $plugin;
71
            }
72
            $last = $plugin;
73
        }
74
        if ($last instanceof Apie) {
75
            return $last->getPlugin($pluginClass);
76
        }
77
        throw new BadConfigurationException('Plugin ' . $pluginClass . ' not found!');
78
    }
79
80
    /**
81
     * Returns first plugin or throw error.
82
     *
83
     * @param string $interface
84
     * @param Throwable $error
85
     * @return object
86
     */
87
    public function first(string $interface, ?Throwable $error): ?object
88
    {
89
        $plugins = $this->getPluginsWithInterface($interface);
90
        if (empty($plugins)) {
91
            if ($error) {
92
                throw $error;
93
            }
94
            return null;
95
        }
96
        return reset($plugins);
97
    }
98
99
    /**
100
     * Iterate over all plugins with a specific interface with a callback.
101
     *
102
     * @param string $interface
103
     * @param callable $callback
104
     * @return array
105
     */
106
    public function each(string $interface, callable $callback)
107
    {
108
        return array_map($callback, $this->getPluginsWithInterface($interface));
109
    }
110
111
    /**
112
     * Merge the results of a getter in a list of plugins into a single array.
113
     *
114
     * @param string $interface
115
     * @param string $getterMethod
116
     * @return array
117
     */
118
    public function merge(string $interface, string $getterMethod): array
119
    {
120
        $res = [];
121
        foreach ($this->getPluginsWithInterface($interface) as $plugin) {
122
            $res = array_merge($res, $plugin->$getterMethod());
123
        }
124
        return $res;
125
    }
126
127
    /**
128
     * Iterate over a getter of a list of plugins and return all return values in a generator.
129
     *
130
     * @param string $interface
131
     * @param string $getterMethod
132
     * @return Generator
133
     */
134
    public function combine(string $interface, string $getterMethod): Generator
135
    {
136
        foreach ($this->getPluginsWithInterface($interface) as $plugin) {
137
            yield $plugin->$getterMethod();
138
        }
139
    }
140
}
141