Completed
Push — master ( fac124...ff4c77 )
by Márk
10s
created

ClassDiscovery::findOneByType()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 32
rs 6.7272
cc 7
eloc 17
nc 6
nop 1
1
<?php
2
3
namespace Http\Discovery;
4
5
use Http\Discovery\Exception\DiscoveryFailedException;
6
use Http\Discovery\Exception\StrategyUnavailableException;
7
8
/**
9
 * Registry that based find results on class existence.
10
 *
11
 * @author David de Boer <[email protected]>
12
 * @author Márk Sági-Kazár <[email protected]>
13
 * @author Tobias Nyholm <[email protected]>
14
 */
15
abstract class ClassDiscovery
16
{
17
    /**
18
     * A list of strategies to find classes.
19
     *
20
     * @var array
21
     */
22
    private static $strategies = [
23
        Strategy\Puli::class,
24
        Strategy\CommonClassesStrategy::class,
25
    ];
26
27
    /**
28
     * Discovery cache to make the second time we use discovery faster.
29
     *
30
     * @var array
31
     */
32
    private static $cache = [];
33
34
    /**
35
     * Finds a class.
36
     *
37
     * @param string $type
38
     *
39
     * @return string
40
     *
41
     * @throws DiscoveryFailedException
42
     */
43
    protected static function findOneByType($type)
44
    {
45
        // Look in the cache
46
        if (null !== ($class = self::getFromCache($type))) {
47
            return $class;
48
        }
49
50
        $exceptions = [];
51
        foreach (self::$strategies as $strategy) {
52
            try {
53
                $candidates = call_user_func($strategy.'::getCandidates', $type);
54
            } catch (StrategyUnavailableException $e) {
55
                $exceptions[] = $e;
56
                continue;
57
            }
58
59
            foreach ($candidates as $candidate) {
60
                if (isset($candidate['condition'])) {
61
                    if (!self::evaluateCondition($candidate['condition'])) {
62
                        continue;
63
                    }
64
                }
65
66
                // save the result for later use
67
                self::storeInCache($type, $candidate);
68
69
                return $candidate['class'];
70
            }
71
        }
72
73
        throw new DiscoveryFailedException('Could not find resource using any discovery strategy', $exceptions);
74
    }
75
76
    /**
77
     * Get a value from cache.
78
     *
79
     * @param string $type
80
     *
81
     * @return string|null
82
     */
83
    private static function getFromCache($type)
84
    {
85
        if (!isset(self::$cache[$type])) {
86
            return;
87
        }
88
89
        $candidate = self::$cache[$type];
90
        if (!self::evaluateCondition($candidate['condition'])) {
91
            return;
92
        }
93
94
        return $candidate['class'];
95
    }
96
97
    /**
98
     * Store a value in cache.
99
     *
100
     * @param string $type
101
     * @param string $class
102
     */
103
    private static function storeInCache($type, $class)
104
    {
105
        self::$cache[$type] = $class;
106
    }
107
108
    /**
109
     * Set new strategies and clear the cache.
110
     *
111
     * @param array $strategies
112
     */
113
    public static function setStrategies(array $strategies)
114
    {
115
        self::$strategies = $strategies;
116
        self::clearCache();
117
    }
118
119
    /**
120
     * Clear the cache.
121
     */
122
    public static function clearCache()
123
    {
124
        self::$cache = [];
125
    }
126
127
    /**
128
     * Evaulates conditions to boolean.
129
     *
130
     * @param mixed $condition
131
     *
132
     * @return bool
133
     */
134
    protected static function evaluateCondition($condition)
135
    {
136
        if (is_string($condition)) {
137
            // Should be extended for functions, extensions???
138
            return class_exists($condition);
139
        } elseif (is_callable($condition)) {
140
            return $condition();
141
        } elseif (is_bool($condition)) {
142
            return $condition;
143
        } elseif (is_array($condition)) {
144
            $evaluatedCondition = true;
145
146
            // Immediately stop execution if the condition is false
147
            for ($i = 0; $i < count($condition) && false !== $evaluatedCondition; ++$i) {
148
                $evaluatedCondition &= static::evaluateCondition($condition[$i]);
149
            }
150
151
            return $evaluatedCondition;
152
        }
153
154
        return false;
155
    }
156
}
157