1<?php
2
3/*
4 * This file is part of composer/semver.
5 *
6 * (c) Composer <https://github.com/composer>
7 *
8 * For the full copyright and license information, please view
9 * the LICENSE file that was distributed with this source code.
10 */
11
12namespace Composer\Semver;
13
14use Composer\Semver\Constraint\Constraint;
15
16class Semver
17{
18    const SORT_ASC = 1;
19    const SORT_DESC = -1;
20
21    /** @var VersionParser */
22    private static $versionParser;
23
24    /**
25     * Determine if given version satisfies given constraints.
26     *
27     * @param string $version
28     * @param string $constraints
29     *
30     * @return bool
31     */
32    public static function satisfies($version, $constraints)
33    {
34        if (null === self::$versionParser) {
35            self::$versionParser = new VersionParser();
36        }
37
38        $versionParser = self::$versionParser;
39        $provider = new Constraint('==', $versionParser->normalize($version));
40        $parsedConstraints = $versionParser->parseConstraints($constraints);
41
42        return $parsedConstraints->matches($provider);
43    }
44
45    /**
46     * Return all versions that satisfy given constraints.
47     *
48     * @param string[] $versions
49     * @param string   $constraints
50     *
51     * @return string[]
52     */
53    public static function satisfiedBy(array $versions, $constraints)
54    {
55        $versions = array_filter($versions, function ($version) use ($constraints) {
56            return Semver::satisfies($version, $constraints);
57        });
58
59        return array_values($versions);
60    }
61
62    /**
63     * Sort given array of versions.
64     *
65     * @param string[] $versions
66     *
67     * @return string[]
68     */
69    public static function sort(array $versions)
70    {
71        return self::usort($versions, self::SORT_ASC);
72    }
73
74    /**
75     * Sort given array of versions in reverse.
76     *
77     * @param string[] $versions
78     *
79     * @return string[]
80     */
81    public static function rsort(array $versions)
82    {
83        return self::usort($versions, self::SORT_DESC);
84    }
85
86    /**
87     * @param string[] $versions
88     * @param int      $direction
89     *
90     * @return string[]
91     */
92    private static function usort(array $versions, $direction)
93    {
94        if (null === self::$versionParser) {
95            self::$versionParser = new VersionParser();
96        }
97
98        $versionParser = self::$versionParser;
99        $normalized = array();
100
101        // Normalize outside of usort() scope for minor performance increase.
102        // Creates an array of arrays: [[normalized, key], ...]
103        foreach ($versions as $key => $version) {
104            $normalizedVersion = $versionParser->normalize($version);
105            $normalizedVersion = $versionParser->normalizeDefaultBranch($normalizedVersion);
106            $normalized[] = array($normalizedVersion, $key);
107        }
108
109        usort($normalized, function (array $left, array $right) use ($direction) {
110            if ($left[0] === $right[0]) {
111                return 0;
112            }
113
114            if (Comparator::lessThan($left[0], $right[0])) {
115                return -$direction;
116            }
117
118            return $direction;
119        });
120
121        // Recreate input array, using the original indexes which are now in sorted order.
122        $sorted = array();
123        foreach ($normalized as $item) {
124            $sorted[] = $versions[$item[1]];
125        }
126
127        return $sorted;
128    }
129}
130