StabilityFlags::getPattern()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php namespace Arcanedev\Composer\Entities;
2
3
use Composer\Package\BasePackage;
4
use Composer\Package\Version\VersionParser;
5
6
/**
7
 * Class     StabilityFlags
8
 *
9
 * @package  Arcanedev\Composer\Entities
10
 * @author   ARCANEDEV <[email protected]>
11
 */
12
class StabilityFlags
13
{
14
    /* -----------------------------------------------------------------
15
     |  Properties
16
     | -----------------------------------------------------------------
17
     */
18
19
    /**
20
     * Current package name => stability mappings.
21
     *
22
     * @var array
23
     */
24
    protected $flags;
25
26
    /**
27
     * Current default minimum stability.
28
     *
29
     * @var int
30
     */
31
    protected $minimumStability;
32
33
    /* -----------------------------------------------------------------
34
     |  Constructor
35
     | -----------------------------------------------------------------
36
     */
37
38
    /**
39
     * Make StabilityFlags instance.
40
     *
41
     * @param  array  $flags
42
     * @param  int    $minimumStability
43
     */
44 87
    public function __construct(
45
        array $flags = [],
46
        $minimumStability = BasePackage::STABILITY_STABLE
47
    ) {
48 87
        $this->flags            = $flags;
49 87
        $this->minimumStability = $this->getStabilityInteger($minimumStability);
50 87
    }
51
52
    /* ------------------------------------------------------------------------------------------------
53
     |  Getters & Setters
54
     | ------------------------------------------------------------------------------------------------
55
     */
56
    /**
57
     * Get the stability value for a given string.
58
     *
59
     * @param  string  $name
60
     *
61
     * @return int
62
     */
63 87
    private function getStabilityInteger($name)
64
    {
65 87
        $name = VersionParser::normalizeStability($name);
66
67 87
        return BasePackage::$stabilities[$name] ?? BasePackage::STABILITY_STABLE;
68
    }
69
70
    /**
71
     * Get regex pattern.
72
     *
73
     * @return string
74
     */
75 87
    private function getPattern()
76
    {
77 87
        $stabilities = BasePackage::$stabilities;
78
79 87
        return '/^[^@]*?@(' . implode('|', array_keys($stabilities)) . ')$/i';
80
    }
81
82
    /* -----------------------------------------------------------------
83
     |  Main Methods
84
     | -----------------------------------------------------------------
85
     */
86
87
    /**
88
     * Make StabilityFlags and extract stability flags.
89
     *
90
     * @param  array  $flags
91
     * @param  int    $minimumStability
92
     * @param  array  $requires
93
     *
94
     * @return array
95
     */
96 54
    public static function extract(array $flags, $minimumStability, array $requires)
97
    {
98 54
        return (new static($flags, $minimumStability))->extractAll($requires);
99
    }
100
101
    /**
102
     * Extract and merge stability flags from the given collection of
103
     * requires with another collection of stability flags.
104
     *
105
     * @param  array  $requires  New package name => link mappings
106
     *
107
     * @return array             Unified package name => stability mappings
108
     */
109 87
    public function extractAll(array $requires)
110
    {
111 87
        $flags = [];
112
113 87
        foreach ($requires as $name => $link) {
114
            /** @var \Composer\Package\Link $link */
115 87
            $version      = $link->getPrettyConstraint();
116 87
            $stability    = $this->extractStability($version);
117 87
            $name         = strtolower($name);
118 87
            $flags[$name] = max($stability, $this->getCurrentStability($name));
119
        }
120
121
        return array_filter($flags, function($v) {
122 87
            return $v !== null;
123 87
        });
124
    }
125
126
    /* -----------------------------------------------------------------
127
     |  Other Methods
128
     | -----------------------------------------------------------------
129
     */
130
131
    /**
132
     * Extract the most unstable explicit stability (eg '@dev') from a version specification.
133
     *
134
     * @param  string  $version
135
     *
136
     * @return int|null
137
     */
138 87
    protected function getExplicitStability($version)
139
    {
140 87
        $found   = null;
141 87
        $pattern = $this->getPattern();
142
143 87
        foreach (static::splitConstraints($version) as $constraint) {
144 87
            if ( ! preg_match($pattern, $constraint, $match)) {
145 66
                continue;
146
            }
147
148 39
            $stability = $this->getStabilityInteger($match[1]);
149 39
            $found     = max($stability, $found);
150
        }
151
152 87
        return $found;
153
    }
154
155
    /**
156
     * Extract stability.
157
     *
158
     * @param  string  $version
159
     *
160
     * @return mixed
161
     */
162 87
    private function extractStability($version)
163
    {
164 87
        $stability = $this->getExplicitStability($version);
165
166 87
        if ($stability === null) {
167 63
            $stability = $this->getParsedStability($version);
168
        }
169
170 87
        return $stability;
171
    }
172
173
    /**
174
     * Get the current stability of a given package.
175
     *
176
     * @param  string  $name
177
     *
178
     * @return int|null
179
     */
180 87
    protected function getCurrentStability($name)
181
    {
182 87
        return $this->flags[$name] ?? null;
183
    }
184
185
    /**
186
     * Get the stability of a version
187
     *
188
     * @param  string  $version
189
     *
190
     * @return int|null
191
     */
192 63
    private function getParsedStability($version)
193
    {
194
        // Drop aliasing if used
195 63
        $version   = preg_replace('/^([^,\s@]+) as .+$/', '$1', $version);
196 63
        $stability = $this->getStabilityInteger(VersionParser::parseStability($version));
197
198 63
        if ($stability === BasePackage::STABILITY_STABLE || $this->minimumStability > $stability) {
199
            // Ignore if 'stable' or more stable than the global minimum
200 45
            $stability = null;
201
        }
202
203 63
        return $stability;
204
    }
205
206
    /**
207
     * Split a version specification into a list of version constraints.
208
     *
209
     * @param  string  $version
210
     *
211
     * @return array
212
     */
213 87
    protected static function splitConstraints($version)
214
    {
215 87
        $found   = [];
216 87
        $pattern = '/(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)/';
217
218 87
        foreach (preg_split('/\s*\|\|?\s*/', trim($version)) as $constraints) {
219 87
            $andConstraints = preg_split($pattern, $constraints);
220
221 87
            foreach ($andConstraints as $constraint) {
222 87
                $found[] = $constraint;
223
            }
224
        }
225
226 87
        return $found;
227
    }
228
}
229