UpdateChecker   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 39
dl 0
loc 112
rs 10
c 0
b 0
f 0
wmc 11

3 Methods

Rating   Name   Duplication   Size   Complexity  
A checkForUpdates() 0 24 3
A getVersionSelector() 0 14 2
A findLatestPackage() 0 32 6
1
<?php
2
3
namespace BringYourOwnIdeas\UpdateChecker;
4
5
use BringYourOwnIdeas\Maintenance\Util\ComposerLoader;
6
use Composer\Composer;
7
use Composer\DependencyResolver\Pool;
8
use Composer\Package\BasePackage;
9
use Composer\Package\PackageInterface;
10
use Composer\Package\Version\VersionSelector;
11
use Composer\Repository\CompositeRepository;
12
use SilverStripe\Core\Injector\Injector;
13
14
/**
15
 * The update checker class is provided a {@link Link} object representing a package and uses the Composer API to
16
 * determine the next available updates for the package.
17
 */
18
class UpdateChecker
19
{
20
    /**
21
     * @var VersionSelector
22
     */
23
    protected $versionSelector;
24
25
    /**
26
     * Update types (see {@link ComposerPackageVersion}
27
     *
28
     * @var string
29
     */
30
    const TYPE_AVAILABLE = 'Available';
31
    const TYPE_LATEST = 'Latest';
32
33
    /**
34
     * Checks the given package for available and latest updates, and writes them to data models if found
35
     *
36
     * @param PackageInterface $package
37
     * @param string $constraint
38
     * @return string[]
39
     */
40
    public function checkForUpdates(PackageInterface $package, $constraint)
41
    {
42
        $installedVersion = $package->getPrettyVersion();
43
44
        /** @var Composer $composer */
45
        $composer = Injector::inst()->get(ComposerLoader::class)->getComposer();
46
47
        $updateInformation = [
48
            'Version' => $installedVersion,
49
            'VersionHash' => $package->getSourceReference(),
50
            'VersionConstraint' => $constraint,
51
        ];
52
53
        if ($available = $this->findLatestPackage($package, $constraint, $installedVersion, $composer, true)) {
54
            $updateInformation[self::TYPE_AVAILABLE . 'Version'] = $available->getPrettyVersion();
55
            $updateInformation[self::TYPE_AVAILABLE . 'Hash'] = $available->getSourceReference();
56
        }
57
58
        if ($latest = $this->findLatestPackage($package, $constraint, $installedVersion, $composer, false)) {
59
            $updateInformation[self::TYPE_LATEST . 'Version'] = $latest->getPrettyVersion();
60
            $updateInformation[self::TYPE_LATEST . 'Hash'] = $latest->getSourceReference();
61
        }
62
63
        return $updateInformation;
64
    }
65
66
    /**
67
     * @param Composer $composer
68
     * @return VersionSelector
69
     */
70
    protected function getVersionSelector(Composer $composer)
71
    {
72
        if (!$this->versionSelector) {
73
            // Instantiate a new repository pool, providing the stability flags from the project
74
            $pool = new Pool(
75
                $composer->getPackage()->getMinimumStability(),
76
                $composer->getPackage()->getStabilityFlags()
77
            );
78
            $pool->addRepository(new CompositeRepository($composer->getRepositoryManager()->getRepositories()));
79
80
            $this->versionSelector = new VersionSelector($pool);
81
        }
82
83
        return $this->versionSelector;
84
    }
85
86
    /**
87
     * Given a package, this finds the latest package matching it
88
     *
89
     * Based on Composer's ShowCommand::findLatestPackage
90
     *
91
     * @param PackageInterface $package
92
     * @param string $constraint
93
     * @param string $installedVersion
94
     * @param Composer $composer
95
     * @param bool $minorOnly
96
     * @return bool|PackageInterface
97
     */
98
    protected function findLatestPackage(
99
        PackageInterface $package,
100
        $constraint,
101
        $installedVersion,
102
        Composer $composer,
103
        $minorOnly = false
104
    ) {
105
        // find the latest version allowed in this pool
106
        $name = $package->getName();
107
        $versionSelector = $this->getVersionSelector($composer);
108
        $stability = $composer->getPackage()->getMinimumStability();
109
        $flags = $composer->getPackage()->getStabilityFlags();
110
        if (isset($flags[$name])) {
111
            $stability = array_search($flags[$name], BasePackage::$stabilities, true);
112
        }
113
114
        $bestStability = $stability;
115
        if ($composer->getPackage()->getPreferStable()) {
116
            $bestStability = $composer->getPackage()->getStability();
117
        }
118
119
        $targetVersion = null;
120
        if (0 === strpos($installedVersion, 'dev-')) {
121
            $targetVersion = $installedVersion;
122
        }
123
124
        if ($targetVersion === null && $minorOnly) {
125
            // Use the semver constraint to determine the next available version
126
            $targetVersion = $constraint;
127
        }
128
129
        return $versionSelector->findBestCandidate($name, $targetVersion, null, $bestStability);
0 ignored issues
show
Bug introduced by Robbie Averill
It seems like $bestStability can also be of type false; however, parameter $preferredStability of Composer\Package\Version...or::findBestCandidate() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
        return $versionSelector->findBestCandidate($name, $targetVersion, null, /** @scrutinizer ignore-type */ $bestStability);
Loading history...
130
    }
131
}
132