Completed
Push — master ( 55accb...6b95b9 )
by
unknown
17:55
created

UpdateChecker::recordUpdate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 2
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 Package;
13
use DataObject;
14
use Injector;
15
16
/**
17
 * The update checker class is provided a {@link Link} object representing a package and uses the Composer API to
18
 * determine the next available updates for the package.
19
 */
20
class UpdateChecker
21
{
22
    /**
23
     * @var VersionSelector
24
     */
25
    protected $versionSelector;
26
27
    /**
28
     * Update types (see {@link ComposerPackageVersion}
29
     *
30
     * @var string
31
     */
32
    const TYPE_AVAILABLE = 'Available';
33
    const TYPE_LATEST = 'Latest';
34
35
    /**
36
     * Checks the given package for available and latest updates, and writes them to data models if found
37
     *
38
     * @param PackageInterface $package
39
     * @param string $constraint
40
     * @return string[]
41
     */
42
    public function checkForUpdates(PackageInterface $package, $constraint)
43
    {
44
        $installedVersion = $package->getPrettyVersion();
45
46
        /** @var Composer $composer */
47
        $composer = Injector::inst()->get(ComposerLoader::class)->getComposer();
48
49
        $updateInformation = [
50
            'Version' => $installedVersion,
51
            'VersionHash' => $package->getSourceReference(),
52
            'VersionConstraint' => $constraint,
53
        ];
54
55 View Code Duplication
        if ($available = $this->findLatestPackage($package, $constraint, $installedVersion, $composer, true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
56
            $updateInformation[self::TYPE_AVAILABLE . 'Version'] = $available->getPrettyVersion();
57
            $updateInformation[self::TYPE_AVAILABLE . 'Hash'] = $available->getSourceReference();
58
        }
59
60 View Code Duplication
        if ($latest = $this->findLatestPackage($package, $constraint, $installedVersion, $composer, false)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
61
            $updateInformation[self::TYPE_LATEST . 'Version'] = $latest->getPrettyVersion();
62
            $updateInformation[self::TYPE_LATEST . 'Hash'] = $latest->getSourceReference();
63
        }
64
65
        return $updateInformation;
66
    }
67
68
    /**
69
     * @param Composer $composer
70
     * @return VersionSelector
71
     */
72
    protected function getVersionSelector(Composer $composer)
73
    {
74
        if (!$this->versionSelector) {
75
            // Instantiate a new repository pool, providing the stability flags from the project
76
            $pool = new Pool(
77
                $composer->getPackage()->getMinimumStability(),
78
                $composer->getPackage()->getStabilityFlags()
79
            );
80
            $pool->addRepository(new CompositeRepository($composer->getRepositoryManager()->getRepositories()));
81
82
            $this->versionSelector = new VersionSelector($pool);
83
        }
84
85
        return $this->versionSelector;
86
    }
87
88
    /**
89
     * Given a package, this finds the latest package matching it
90
     *
91
     * Based on Composer's ShowCommand::findLatestPackage
92
     *
93
     * @param PackageInterface $package
94
     * @param string $constraint
95
     * @param string $installedVersion
96
     * @param Composer $composer
97
     * @param bool $minorOnly
98
     * @return bool|PackageInterface
99
     */
100
    protected function findLatestPackage(
101
        PackageInterface $package,
102
        $constraint,
103
        $installedVersion,
104
        Composer $composer,
105
        $minorOnly = false
106
    ) {
107
        // find the latest version allowed in this pool
108
        $name = $package->getName();
109
        $versionSelector = $this->getVersionSelector($composer);
110
        $stability = $composer->getPackage()->getMinimumStability();
111
        $flags = $composer->getPackage()->getStabilityFlags();
112
        if (isset($flags[$name])) {
113
            $stability = array_search($flags[$name], BasePackage::$stabilities, true);
114
        }
115
116
        $bestStability = $stability;
117
        if ($composer->getPackage()->getPreferStable()) {
118
            $bestStability = $composer->getPackage()->getStability();
119
        }
120
121
        $targetVersion = null;
122
        if (0 === strpos($installedVersion, 'dev-')) {
123
            $targetVersion = $installedVersion;
124
        }
125
126
        if ($targetVersion === null && $minorOnly) {
127
            // Use the semver constraint to determine the next available version
128
            $targetVersion = $constraint;
129
        }
130
131
        return $versionSelector->findBestCandidate($name, $targetVersion, null, $bestStability);
132
    }
133
}
134