Completed
Push — master ( f81cf6...7fbbb0 )
by Oleg
03:40
created

ConfigGenerator::addUses()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 2
dl 0
loc 8
rs 10
c 0
b 0
f 0
ccs 6
cts 6
cp 1
crap 3
1
<?php
2
declare(strict_types=1);
3
4
namespace SlayerBirden\DFCodeGeneration\Generator\Config;
5
6
use Nette\PhpGenerator\ClassType;
7
use Nette\PhpGenerator\PhpFile;
8
use Nette\PhpGenerator\PhpLiteral;
9
use Nette\PhpGenerator\PhpNamespace;
10
use Nette\PhpGenerator\PsrPrinter;
11
use SlayerBirden\DFCodeGeneration\Code\Printer\NsArrayPrinter;
12
use SlayerBirden\DFCodeGeneration\Generator\Config\Code\CodeFeederInterface;
13
use SlayerBirden\DFCodeGeneration\Generator\DataProvider\DataProviderInterface;
14
use SlayerBirden\DFCodeGeneration\Generator\GeneratorInterface;
15
use SlayerBirden\DFCodeGeneration\Util\ArrayUtils;
16
17
final class ConfigGenerator implements GeneratorInterface
18
{
19
    /**
20
     * @var DataProviderInterface
21
     */
22
    private $dataProvider;
23
    /**
24
     * @var ConfigPartInterface[]
25
     */
26
    private $parts;
27
    /**
28
     * @var array
29
     */
30
    private $currentConfig;
31
    /**
32
     * @var CodeFeederInterface
33
     */
34
    private $codeFeeder;
35
36 2
    public function __construct(
37
        DataProviderInterface $dataProvider,
38
        CodeFeederInterface $codeFeeder,
39
        ConfigPartInterface ...$parts
40
    ) {
41 2
        $this->dataProvider = $dataProvider;
42 2
        $this->parts = $parts;
43 2
        $this->codeFeeder = $codeFeeder;
44 2
    }
45
46 2
    public function generate(): string
47
    {
48 2
        $invoke = [];
49
50 2
        $file = new PhpFile();
51 2
        $file->setStrictTypes();
52 2
        $file->addComment('This file is generated by SlayerBirden\DFCodeGeneration');
53 2
        $namespace = $file->addNamespace($this->getConfigNamespace());
54 2
        $class = $namespace->addClass('ConfigProvider');
55 2
        $class->setFinal();
56
57 2
        foreach ($this->parts as $configPart) {
58 2
            $invoke[$configPart->getCode()] = $configPart->getConfig();
59
        }
60
61 2
        $invoke = ArrayUtils::merge($this->getCurrentConfig(), $invoke);
62 2
        $this->addUses($invoke, $namespace);
63 2
        $this->codeFeeder->feed($invoke, $class, $namespace);
64
65 2
        return (new PsrPrinter())->printFile($file);
66
    }
67
68 2
    public function getClassName(): string
69
    {
70 2
        return $this->getConfigNamespace() . '\\ConfigProvider';
71
    }
72
73 2
    private function getConfigNamespace(): string
74
    {
75 2
        return $this->dataProvider->provide()['config_namespace'];
76
    }
77
78 2
    private function getCurrentConfig(): array
79
    {
80 2
        if ($this->currentConfig === null) {
81 2
            $config = $this->getClassName();
82
83 2
            if (class_exists($config)) {
84
                $this->currentConfig = (new $config())();
85
            } else {
86 2
                $this->currentConfig = [];
87
            }
88
        }
89
90 2
        return $this->currentConfig;
91
    }
92
93 2
    private function addUses(array $config, PhpNamespace $phpNamespace): void
94
    {
95 2
        foreach ($config as $key => $value) {
96 2
            $this->checkRecord($key, $phpNamespace);
97 2
            if (is_array($value)) {
98 2
                $this->addUses($value, $phpNamespace);
99
            } else {
100 2
                $this->checkRecord($value, $phpNamespace);
101
            }
102
        }
103 2
    }
104
105
    /**
106
     * @param mixed $record
107
     * @param PhpNamespace $phpNamespace
108
     */
109 2
    private function checkRecord($record, PhpNamespace $phpNamespace): void
110
    {
111
        // order is important - first check records with ::class
112
        // only after that records just with backslash
113 2
        if (is_string($record) && (strpos($record, '::class') !== false)) {
114 2
            $phpNamespace->addUse(str_replace('::class', '', $record));
115 2
        } elseif (is_string($record) && (strpos($record, '\\') !== false)) {
116 2
            $phpNamespace->addUse($record);
117 2
        } elseif (($record instanceof PhpLiteral) && (strpos((string)$record, '::class') !== false)) {
118 2
            $phpNamespace->addUse(str_replace('::class', '', (string)$record));
119
        }
120 2
    }
121
122 2
    public function getFileName(): string
123
    {
124 2
        return sprintf('src/%s/ConfigProvider.php', $this->dataProvider->provide()['entityClassName']);
125
    }
126
}
127