ComposerLoaderExtension::onAfterBuild()   B
last analyzed

Complexity

Conditions 7
Paths 12

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 7
eloc 11
c 4
b 1
f 0
nc 12
nop 0
dl 0
loc 23
rs 8.8333
1
<?php
2
3
namespace BringYourOwnIdeas\UpdateChecker\Extensions;
4
5
use Composer\Composer;
6
use Composer\Factory;
7
use Composer\IO\NullIO;
8
use Composer\Package\Link;
9
use Composer\Repository\InstalledRepository;
10
use Composer\Repository\RootPackageRepository;
11
use Composer\Repository\RepositoryInterface;
12
use SilverStripe\Core\Environment;
13
use SilverStripe\Core\Extension;
14
15
class ComposerLoaderExtension extends Extension
16
{
17
    /**
18
     * @var Composer
19
     */
20
    protected $composer;
21
22
    /**
23
     * @param Composer $composer
24
     * @return $this
25
     */
26
    public function setComposer(Composer $composer)
27
    {
28
        $this->composer = $composer;
29
        return $this;
30
    }
31
32
    /**
33
     * @return Composer
34
     */
35
    public function getComposer()
36
    {
37
        return $this->composer;
38
    }
39
40
    /**
41
     * Retrieve an array of primary composer dependencies from composer.json.
42
     * Packages are filtered by allowed type.
43
     * Dependencies in composer.json that do not match any of the given types are not returned.
44
     *
45
     * @param array|null $allowedTypes An array of "allowed" package types.
46
     * @return array[]
47
     */
48
    public function getPackages(array $allowedTypes = null)
49
    {
50
        $packages = [];
51
        $repository = $this->getRepository();
52
        foreach ($repository->getPackages() as $package) {
53
            // Filter out packages that are not "allowed types"
54
            if (is_array($allowedTypes) && !in_array($package->getType(), $allowedTypes)) {
55
                continue;
56
            }
57
58
            // Find the constraint used for installation
59
            $constraint = $this->getInstalledConstraint($repository, $package->getName());
60
            $packages[$package->getName()] = [
61
                'constraint' => $constraint,
62
                'package' => $package,
63
            ];
64
        }
65
        return $packages;
66
    }
67
68
    /**
69
     * Provides access to the Composer repository
70
     */
71
    protected function getRepository(): RepositoryInterface
72
    {
73
        /** @var Composer $composer */
74
        $composer = $this->getComposer();
75
        return new InstalledRepository([
76
            new RootPackageRepository($composer->getPackage()),
77
            $composer->getRepositoryManager()->getLocalRepository()
78
        ]);
79
    }
80
81
    /**
82
     * Find all dependency constraints for the given package in the current repository and return the strictest one
83
     */
84
    protected function getInstalledConstraint(InstalledRepository $repository, string $packageName): string
85
    {
86
        $constraints = [];
87
        foreach ($repository->getDependents($packageName) as $dependent) {
88
            /** @var Link $link */
89
            list (, $link) = $dependent;
90
            $constraints[] = $link->getPrettyConstraint() ?? '';
91
        }
92
        usort($constraints, 'version_compare');
93
        return array_pop($constraints);
94
    }
95
96
    /**
97
     * Builds an instance of Composer
98
     */
99
    public function onAfterBuild()
100
    {
101
        // Mock COMPOSER_HOME if it's not defined already. Composer requires one of the two to be set.
102
        if (!Environment::getEnv('COMPOSER_HOME')) {
103
            $home = Environment::getEnv('HOME');
104
            if (!$home || !is_dir($home) || !is_writable($home)) {
105
                // Set our own directory
106
                putenv('COMPOSER_HOME=' . sys_get_temp_dir());
107
            }
108
        }
109
110
        $originalDir = getcwd();
111
112
        if ($originalDir !== BASE_PATH) {
113
            chdir(BASE_PATH);
114
        }
115
116
        /** @var Composer $composer */
117
        $composer = Factory::create(new NullIO());
118
        $this->setComposer($composer);
119
120
        if ($originalDir !== BASE_PATH) {
121
            chdir($originalDir);
122
        }
123
    }
124
}
125