Passed
Pull Request — master (#22)
by Dmitriy
28:42 queued 13:51
created

Resolver::resolveDependencies()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 11
c 0
b 0
f 0
rs 10
cc 3
nc 3
nop 1
1
<?php
2
3
namespace Yiisoft\Composer\Config\Util;
4
5
use Yiisoft\Composer\Config\Builder;
6
use Yiisoft\Composer\Config\Exception\CircularDependencyException;
7
8
/**
9
 * Resolver class.
10
 * Reorders files according to their cross dependencies
11
 * and resolves `$name` paths.
12
 */
13
class Resolver
14
{
15
    private array $dependenciesOrder = [];
16
17
    private array $dependencies = [];
18
19
    private array $following = [];
20
21
    private array $files;
22
23
    public function __construct(array $files)
24
    {
25
        $this->files = $files;
26
27
        $this->collectDependencies($files);
28
        foreach (array_keys($files) as $name) {
29
            $this->followDependencies($name);
30
        }
31
    }
32
33
    public function get(): array
34
    {
35
        $result = [];
36
        foreach ($this->dependenciesOrder as $name) {
37
            $result[$name] = $this->resolveDependencies($this->files[$name]);
38
        }
39
40
        return $result;
41
    }
42
43
    private function resolveDependencies(array $paths): array
44
    {
45
        foreach ($paths as &$path) {
46
            if ($this->isDependency($path)) {
47
                $dependency = $this->parseDependencyName($path);
48
49
                $path = Builder::path($dependency);
50
            }
51
        }
52
53
        return $paths;
54
    }
55
56
    private function followDependencies(string $name): void
57
    {
58
        if (array_key_exists($name, $this->dependenciesOrder)) {
59
            return;
60
        }
61
        if (array_key_exists($name, $this->following)) {
62
            throw new CircularDependencyException($name . ' ' . implode(',', $this->following));
63
        }
64
        $this->following[$name] = $name;
65
        if (array_key_exists($name, $this->dependencies)) {
66
            foreach ($this->dependencies[$name] as $dependency) {
67
                $this->followDependencies($dependency);
68
            }
69
        }
70
        $this->dependenciesOrder[$name] = $name;
71
        unset($this->following[$name]);
72
    }
73
74
    private function collectDependencies(array $files): void
75
    {
76
        foreach ($files as $name => $paths) {
77
            foreach ($paths as $path) {
78
                if ($this->isDependency($path)) {
79
                    $dependencyName = $this->parseDependencyName($path);
80
                    if (!array_key_exists($name, $this->dependencies)) {
81
                        $this->dependencies[$name] = [];
82
                    }
83
                    $this->dependencies[$name][$dependencyName] = $dependencyName;
84
                }
85
            }
86
        }
87
    }
88
89
    private function isDependency(string $path): bool
90
    {
91
        return 0 === strncmp($path, '$', 1);
92
    }
93
94
    private function parseDependencyName(string $path): string
95
    {
96
        return substr($path, 1);
97
    }
98
}
99