Passed
Pull Request — master (#6)
by Dmitriy
10:56
created

PackageFinder::iterateDependencies()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 5
eloc 4
nc 6
nop 2
dl 0
loc 6
rs 9.6111
c 1
b 0
f 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Composer\Config\Package;
6
7
use Composer\Composer;
8
use Yiisoft\Composer\Config\Package;
9
10
class PackageFinder
11
{
12
    /**
13
     * Plain list of all project dependencies (including nested) as provided by composer.
14
     * The list is unordered (chaotic, can be different after every update).
15
     */
16
    protected array $plainList = [];
17
18
    /**
19
     * Ordered list of package in form: package => depth
20
     * For order description @see findPackages.
21
     */
22
    protected array $orderedList = [];
23
24
    private Composer $composer;
25
26
    public function __construct(Composer $composer)
27
    {
28
        $this->composer = $composer;
29
    }
30
31
    /**
32
     * Returns ordered list of packages:
33
     * - listed earlier in the composer.json will get earlier in the list
34
     * - childs before parents.
35
     *
36
     * @return Package[]
37
     */
38
    public function findPackages(): array
39
    {
40
        $root = new Package($this->composer->getPackage(), $this->composer);
41
        $this->plainList[$root->getPrettyName()] = $root;
42
        foreach ($this->composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages() as $package) {
43
            $this->plainList[$package->getPrettyName()] = new Package($package, $this->composer);
44
        }
45
        $this->orderedList = [];
46
        $this->iteratePackage($root, true);
47
48
        $res = [];
49
        foreach (array_keys($this->orderedList) as $name) {
50
            $res[] = $this->plainList[$name];
51
        }
52
53
        return $res;
54
    }
55
56
    /**
57
     * Iterates through package dependencies.
58
     *
59
     * @param Package $package to iterate
60
     * @param bool $includingDev process development dependencies, defaults to not process
61
     */
62
    protected function iteratePackage(Package $package, bool $includingDev = false): void
63
    {
64
        $name = $package->getPrettyName();
65
66
        /// prevent infinite loop in case of circular dependencies
67
        static $processed = [];
68
        if (isset($processed[$name])) {
69
            return;
70
        }
71
72
        $processed[$name] = 1;
73
74
        /// package depth in dependency hierarchy
75
        static $depth = 0;
76
        ++$depth;
77
78
        $this->iterateDependencies($package);
79
        if ($includingDev) {
80
            $this->iterateDependencies($package, true);
81
        }
82
        if (!isset($this->orderedList[$name])) {
83
            $this->orderedList[$name] = $depth;
84
        }
85
86
        --$depth;
87
    }
88
89
    /**
90
     * Iterates dependencies of the given package.
91
     *
92
     * @param Package $package
93
     * @param bool $dev which dependencies to iterate: true - dev, default - general
94
     */
95
    protected function iterateDependencies(Package $package, bool $dev = false): void
96
    {
97
        $deps = $dev ? $package->getDevRequires() : $package->getRequires();
98
        foreach (array_keys($deps) as $target) {
99
            if (isset($this->plainList[$target]) && empty($this->orderedList[$target])) {
100
                $this->iteratePackage($this->plainList[$target]);
101
            }
102
        }
103
    }
104
}
105