Passed
Push — master ( f5390f...ff2936 )
by Alexander
02:09
created

PackageFinder   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Test Coverage

Coverage 91.67%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 13
eloc 36
c 1
b 0
f 0
dl 0
loc 101
ccs 33
cts 36
cp 0.9167
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A iteratePackage() 0 25 4
A __construct() 0 5 1
A iterateDependencies() 0 6 5
A findPackages() 0 16 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Composer\Config\Package;
6
7
use Composer\Package\PackageInterface;
8
use Yiisoft\Composer\Config\Package;
9
10
final 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
    private array $plainList = [];
17
18
    /**
19
     * Ordered list of package in form: package => depth.
20
     * For order description see {@see findPackages()}.
21
     */
22
    private array $orderedList = [];
23
24
    private PackageInterface $rootPackage;
25
26
    /**
27
     * @var PackageInterface[]
28
     */
29
    private array $packages;
30
31
    private string $vendorDir;
32
33 1
    public function __construct(string $vendorDir, PackageInterface $rootPackage, array $packages)
34
    {
35 1
        $this->rootPackage = $rootPackage;
36 1
        $this->packages = $packages;
37 1
        $this->vendorDir = $vendorDir;
38 1
    }
39
40
    /**
41
     * Returns ordered list of packages:
42
43
     * - Packages listed earlier in the composer.json will get earlier in the list.
44
     * - Children are listed before parents.
45
     *
46
     * @return Package[]
47
     */
48 1
    public function findPackages(): array
49
    {
50 1
        $root = new Package($this->rootPackage, $this->vendorDir);
51 1
        $this->plainList[$root->getPrettyName()] = $root;
52 1
        foreach ($this->packages as $package) {
53
            $this->plainList[$package->getPrettyName()] = new Package($package, $this->vendorDir);
54
        }
55 1
        $this->orderedList = [];
56 1
        $this->iteratePackage($root, true);
57
58 1
        $result = [];
59 1
        foreach (array_keys($this->orderedList) as $name) {
60 1
            $result[] = $this->plainList[$name];
61
        }
62
63 1
        return $result;
64
    }
65
66
    /**
67
     * Iterates through package dependencies.
68
     *
69
     * @param Package $package to iterate.
70
     * @param bool $includingDev process development dependencies, defaults to not process.
71
     */
72 1
    private function iteratePackage(Package $package, bool $includingDev = false): void
73
    {
74 1
        $name = $package->getPrettyName();
75
76
        // prevent infinite loop in case of circular dependencies
77 1
        static $processed = [];
78 1
        if (array_key_exists($name, $processed)) {
79
            return;
80
        }
81
82 1
        $processed[$name] = 1;
83
84
        // package depth in dependency hierarchy
85 1
        static $depth = 0;
86 1
        ++$depth;
87
88 1
        $this->iterateDependencies($package);
89 1
        if ($includingDev) {
90 1
            $this->iterateDependencies($package, true);
91
        }
92 1
        if (!array_key_exists($name, $this->orderedList)) {
93 1
            $this->orderedList[$name] = $depth;
94
        }
95
96 1
        --$depth;
97 1
    }
98
99
    /**
100
     * Iterates dependencies of the given package.
101
     *
102
     * @param Package $package
103
     * @param bool $dev type of dependencies to iterate: true - dev, default - general.
104
     */
105 1
    private function iterateDependencies(Package $package, bool $dev = false): void
106
    {
107 1
        $dependencies = $dev ? $package->getDevRequires() : $package->getRequires();
108 1
        foreach (array_keys($dependencies) as $target) {
109 1
            if (array_key_exists($target, $this->plainList) && empty($this->orderedList[$target])) {
110
                $this->iteratePackage($this->plainList[$target]);
111
            }
112
        }
113 1
    }
114
}
115