Passed
Push — master ( a228a3...2f45dd )
by Chris
14:02
created

AbstractClassPrinter::finishClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 0
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 2
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php
2
3
namespace Leonidas\Console\Library\Abstracts;
4
5
use Leonidas\Console\Library\PsrPrinterFactory;
6
use Nette\PhpGenerator\ClassType;
7
use Nette\PhpGenerator\InterfaceType;
0 ignored issues
show
Bug introduced by
The type Nette\PhpGenerator\InterfaceType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Nette\PhpGenerator\Method;
9
use Nette\PhpGenerator\PhpFile;
10
use Nette\PhpGenerator\PhpNamespace;
11
use Nette\PhpGenerator\Printer;
12
use Nette\PhpGenerator\TraitType;
0 ignored issues
show
Bug introduced by
The type Nette\PhpGenerator\TraitType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
14
abstract class AbstractClassPrinter
15
{
16
    public const CORE = 'core';
17
18
    protected const SIGNATURES = [];
19
20
    protected string $namespace;
21
22
    protected string $class;
23
24
    public function __construct(string $namespace, string $class)
25
    {
26
        $this->namespace = $namespace;
27
        $this->class = $class;
28
    }
29
30
    public function printFile(): string
31
    {
32
        return $this->print($this->getDefaultSignatures());
33
    }
34
35
    protected function print(array $methods): string
36
    {
37
        $file = new PhpFile();
38
        $namespace = $file->addNamespace($this->namespace);
39
        $class = $this->setupClass($namespace);
40
41
        if (!$class->isInterface()) {
42
            $file->setStrictTypes(true);
43
        }
44
45
        $this->addMethods($class, $methods);
46
        $this->finishClass($class);
47
48
        return $this->getPrinter()->printFile($file);
49
    }
50
51
    protected function getPrinter(): Printer
52
    {
53
        return PsrPrinterFactory::create();
54
    }
55
56
    protected function getDefaultSignatures(): array
57
    {
58
        return static::SIGNATURES;
59
    }
60
61
    /**
62
     * @param ClassType|InterfaceType|TraitType $class
63
     * @param array<string,array<string,string>> $signatures
64
     */
65
    protected function addMethods($class, array $signatures): void
66
    {
67
        foreach ($signatures as $method => $signature) {
68
            $this->addMethod($class, $method, $signature);
69
        }
70
    }
71
72
    /**
73
     * @param ClassType|InterfaceType|TraitType $class
74
     */
75
    protected function addMethod($class, string $name, array $signature): void
76
    {
77
        $call = $signature['call'] ?? $name;
78
79
        $swap = $this->getMethodPassReplacements();
80
        $pass = str_replace($swap[0], $swap[1], $signature['pass'] ?? '');
81
82
        $swap = $this->getMethodGiveReplacements();
83
        $return = str_replace(
84
            [...$swap[0], ...$strip = ['?', '&'], '$this'],
0 ignored issues
show
Bug introduced by
array($swap[0], $strip =...ray('?', '&'), '$this') of type array<integer,array|array<integer,string>|string> is incompatible with the type string|string[] expected by parameter $search of str_replace(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

84
            /** @scrutinizer ignore-type */ [...$swap[0], ...$strip = ['?', '&'], '$this'],
Loading history...
85
            [...$swap[1], ...$this->mapSymbols($strip), $this->getClassFqn()],
0 ignored issues
show
Bug introduced by
array($swap[1], $this->m..., $this->getClassFqn()) of type array<integer,array|string> is incompatible with the type string|string[] expected by parameter $replace of str_replace(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

85
            /** @scrutinizer ignore-type */ [...$swap[1], ...$this->mapSymbols($strip), $this->getClassFqn()],
Loading history...
86
            $give = $signature['give'] ?? 'void'
87
        );
88
89
        $method = $class->addMethod($name)
90
            ->setReturnNullable(str_starts_with($give, '?'))
91
            ->setReturnReference(str_starts_with($give, '&'))
92
            ->setReturnType($return)
93
            ->setPublic();
94
95
        if (!$class->isInterface()) {
96
            $method->setBody($this->getMethodBody($call, $pass, $give));
97
        }
98
99
        $params = ($take = $signature['take'] ?? false)
100
            ? explode(', ', $take)
101
            : [];
102
103
        foreach ($params as $param) {
104
            $this->addParameter($method, $param);
105
        }
106
107
        if ('$this' === $give) {
108
            $method->addComment('@return ' . '$this');
109
        }
110
    }
111
112
    protected function getClassFqn(): string
113
    {
114
        return $this->namespace . '\\' . $this->class;
115
    }
116
117
    protected function getMethodPassReplacements(): array
118
    {
119
        return [[], []];
120
    }
121
122
    protected function getMethodGiveReplacements(): array
123
    {
124
        return [[], []];
125
    }
126
127
    protected function getMethodBody(string $call, string $pass, string $give): string
128
    {
129
        $action = sprintf('$this->%s->%s(%s);', static::CORE, $call, $pass);
130
131
        return ('void' === $give) ? $action : 'return ' . $action;
132
    }
133
134
    protected function addParameter(Method $method, string $param): void
135
    {
136
        $parts = explode(' ', $param);
137
138
        $swap = $this->getParameterTypeReplacements();
139
        $type = str_replace(
140
            [...$swap[0], ...$strip = ['*']],
0 ignored issues
show
Bug introduced by
array($swap[0], $strip = array('*')) of type array<integer,array|array<integer,string>> is incompatible with the type string|string[] expected by parameter $search of str_replace(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
            /** @scrutinizer ignore-type */ [...$swap[0], ...$strip = ['*']],
Loading history...
141
            [...$swap[1], ...$this->mapSymbols($strip)],
0 ignored issues
show
Bug introduced by
array($swap[1], $this->mapSymbols($strip)) of type array<integer,array> is incompatible with the type string|string[] expected by parameter $replace of str_replace(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
            /** @scrutinizer ignore-type */ [...$swap[1], ...$this->mapSymbols($strip)],
Loading history...
142
            $parts[0]
143
        );
144
145
        $swap = $this->getParameterNameReplacements();
146
        $name = str_replace(
147
            [...$swap[0], ...$strip = ['$', '?', '&', '...']],
0 ignored issues
show
Bug introduced by
array($swap[0], $strip =...('$', '?', '&', '...')) of type array<integer,array|array<integer,string>> is incompatible with the type string|string[] expected by parameter $search of str_replace(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

147
            /** @scrutinizer ignore-type */ [...$swap[0], ...$strip = ['$', '?', '&', '...']],
Loading history...
148
            [...$swap[1], ...$this->mapSymbols($strip)],
149
            $parts[1]
150
        );
151
152
        $method->setVariadic(str_starts_with($parts[1], '...'));
153
154
        $parameter = $method->addParameter($name)
155
            ->setNullable(str_starts_with($parts[1], '?'))
156
            ->setReference(str_starts_with($parts[1], '&'))
157
            ->setType($type);
158
159
        if ($default = $parts[3] ?? false) {
160
            if ('null' === $default) {
161
                $default = null;
162
            } elseif ('true' === $default) {
163
                $default = true;
164
            } elseif ('false' === $default) {
165
                $default = false;
166
            } elseif (is_numeric($default)) {
167
                $default = (int) $default;
168
            } elseif (is_string($default)) {
0 ignored issues
show
introduced by
The condition is_string($default) is always true.
Loading history...
169
                $default = trim($default, '\'"');
170
            }
171
172
            $parameter->setDefaultValue($default);
173
        }
174
    }
175
176
    protected function mapSymbols(array $symbols): array
177
    {
178
        return array_pad([], count($symbols), '');
179
    }
180
181
    protected function getParameterTypeReplacements(): array
182
    {
183
        return [[], []];
184
    }
185
186
    protected function getParameterNameReplacements(): array
187
    {
188
        return [[], []];
189
    }
190
191
    /**
192
     * @param ClassType|InterfaceType|TraitType $class
193
     */
194
    protected function finishClass($class): void
195
    {
196
        //
197
    }
198
199
    /**
200
     * @return ClassType|TraitType|InterfaceType
201
     */
202
    abstract protected function setupClass(PhpNamespace $namespace);
203
}
204