Passed
Push — master ( afb49b...f08be5 )
by Dorian
01:45
created

Kernel::illuminateObjectWithAwareness()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 4
nop 2
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace App;
4
5
use App\Domain\Content;
6
use App\Domain\Path;
7
use App\Domain\PathPart;
8
use App\Domain\ProjectRootPathAware;
9
use App\Domain\RootPathPartAware;
10
use App\UI\UserInterface;
11
use Symfony\Component\Filesystem\Filesystem;
12
use Symfony\Component\Finder\Finder;
13
use Symfony\Component\Yaml\Yaml;
14
15
final class Kernel
16
{
17
    /** @var string */
18
    private $projectDir;
19
20
    /** @var string */
21
    private $configDir;
22
23
    /**
24
     * @param string $projectDir
25
     */
26
    public function __construct(string $projectDir)
27
    {
28
        $this->projectDir = rtrim($projectDir, DIRECTORY_SEPARATOR);
29
        $this->configDir = $projectDir.DIRECTORY_SEPARATOR.'config';
30
    }
31
32
    /**
33
     * @param \App\UI\UserInterface $ui
34
     * @param string $singleConfigFilePath
35
     *
36
     * @throws \RuntimeException
37
     * @throws \Symfony\Component\Filesystem\Exception\IOException
38
     * @throws \Symfony\Component\Yaml\Exception\ParseException
39
     */
40
    public function __invoke(UserInterface $ui, $singleConfigFilePath = ''): void
41
    {
42
        $configFilesPaths = !empty($singleConfigFilePath)
43
            ? [$this->getConfigAbsoluteFilePath($singleConfigFilePath)]
44
            : $this->getAllConfigFilesPaths();
45
46
        foreach ($configFilesPaths as $configFilePath) {
47
            $ui->write(
48
                sprintf(
49
                    'Processing configuration file "<info>%s</info>"... ',
50
                    $this->getConfigRelativeFilePath($configFilePath)
51
                )
52
            );
53
            $config = (array) Yaml::parseFile($configFilePath);
54
            $config['enabled'] = $config['enabled'] ?? true;
55
56
            if (!$config['enabled']) {
57
                $ui->writeln('<info>Skipped.</info>'.PHP_EOL);
58
                continue;
59
            }
60
            $ui->writeln(PHP_EOL);
61
62
            $rootPathPart = $this->getRootPathPart($config['path_part'] ?? []);
63
64
            foreach ((array) $config['sources'] as $sources) {
65
                foreach ((array) $sources as $sourceClassName => $sourceData) {
66
67
                    /** @var \App\Domain\Source $source */
68
                    $source = new $sourceClassName($ui, $sourceData['config'] ?? []);
69
                    $this->illuminateObjectWithAwareness($source, $rootPathPart);
70
71
                    // Add the root path part to the contents' path
72
                    $contents = $source->getContents()
73
                        ->map(function (Content $content) use ($rootPathPart) {
74
                            $content->getPath()->add($rootPathPart);
75
76
                            return $content;
77
                        });
78
79
                    foreach ((array) $sourceData['processors'] as $processors) {
80
                        foreach ((array) $processors as $processorClassName => $processorData) {
81
82
                            /** @var \App\Domain\ContentsProcessor $processor */
83
                            $processor = new $processorClassName($ui, $processorData['config'] ?? []);
84
                            $this->illuminateObjectWithAwareness($processor, $rootPathPart);
85
                            $processor->processContents(clone $contents);
86
                        }
87
                    }
88
                }
89
            }
90
        }
91
    }
92
93
    /**
94
     * @return array
95
     */
96
    private function getAllConfigFilesPaths(): array
97
    {
98
        $paths = [];
99
100
        foreach ((new Finder())->in($this->configDir)->files()->sortByName()->name('*.yml')->getIterator() as $file) {
101
            $paths[] = $file->getRealPath();
102
        }
103
104
        return $paths;
105
    }
106
107
    /**
108
     * @param array $config
109
     *
110
     * @return \App\Domain\PathPart
111
     *
112
     * @throws \RuntimeException
113
     * @throws \Symfony\Component\Filesystem\Exception\IOException
114
     */
115
    private function getRootPathPart(array $config): PathPart
116
    {
117
        $config['substitutions'] = ['%project_root%' => $this->projectDir] + ($config['substitutions'] ?? []);
118
        $rootPathPart = new PathPart($config);
119
120
        // Try to create the root directory... 'cause if it fails, nothing will work.
121
        (new Filesystem())->mkdir($rootPathPart->getPath());
122
123
        return $rootPathPart;
124
    }
125
126
    /**
127
     * @param string $configFilePath
128
     *
129
     * @return string
130
     */
131
    private function getConfigRelativeFilePath(string $configFilePath): string
132
    {
133
        return (string) str_replace($this->projectDir.DIRECTORY_SEPARATOR, '', $configFilePath);
134
    }
135
136
    /**
137
     * @param string $configFilePath
138
     *
139
     * @return string
140
     * @throws \RuntimeException
141
     */
142
    private function getConfigAbsoluteFilePath(string $configFilePath): string
143
    {
144
        if (DIRECTORY_SEPARATOR === $configFilePath{0}) {
145
            return $configFilePath;
146
        }
147
148
        return $this->projectDir.DIRECTORY_SEPARATOR.$configFilePath;
149
    }
150
151
    /**
152
     * @param object $object
153
     * @param PathPart $rootPathPart
154
     */
155
    private function illuminateObjectWithAwareness($object, PathPart $rootPathPart): void
156
    {
157
        if ($object instanceof RootPathPartAware) {
158
            $object->setRootPathPart($rootPathPart);
159
        }
160
        if ($object instanceof ProjectRootPathAware) {
161
            $object->setProjectRootPath(new Path([new PathPart(['path' => $this->projectDir])]));
162
        }
163
    }
164
}
165