Passed
Push — master ( f5c22c...929873 )
by Chris
16:12
created

AbstractClassPrinter::getClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
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 getNamespace(): string
31
    {
32
        return $this->namespace;
33
    }
34
35
    public function getClass(): string
36
    {
37
        return $this->class;
38
    }
39
40
    public function printFile(): string
41
    {
42
        return $this->print($this->getDefaultSignatures());
43
    }
44
45
    protected function print(array $methods): string
46
    {
47
        $file = new PhpFile();
48
        $namespace = $file->addNamespace($this->namespace);
49
        $class = $this->setupClass($namespace);
50
51
        if (!$class->isInterface()) {
52
            $file->setStrictTypes(true);
53
        }
54
55
        $this->addMethods($class, $methods);
56
        $this->finishClass($class);
57
58
        return $this->getPrinter()->printFile($file);
59
    }
60
61
    protected function getPrinter(): Printer
62
    {
63
        return PsrPrinterFactory::create();
64
    }
65
66
    protected function getDefaultSignatures(): array
67
    {
68
        return static::SIGNATURES;
69
    }
70
71
    /**
72
     * @param ClassType|InterfaceType|TraitType $class
73
     * @param array<string,array<string,string>> $signatures
74
     */
75
    protected function addMethods($class, array $signatures): void
76
    {
77
        foreach ($signatures as $method => $signature) {
78
            $this->addMethod($class, $method, $signature);
79
        }
80
    }
81
82
    /**
83
     * @param ClassType|InterfaceType|TraitType $class
84
     */
85
    protected function addMethod($class, string $name, array $signature): void
86
    {
87
        $call = $signature['call'] ?? $name;
88
89
        $swap = $this->getMethodPassReplacements();
90
        $pass = str_replace($swap[0], $swap[1], $signature['pass'] ?? '');
91
92
        $swap = $this->getMethodGiveReplacements();
93
        $return = str_replace(
94
            [...$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

94
            /** @scrutinizer ignore-type */ [...$swap[0], ...$strip = ['?', '&'], '$this'],
Loading history...
95
            [...$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

95
            /** @scrutinizer ignore-type */ [...$swap[1], ...$this->mapSymbols($strip), $this->getClassFqn()],
Loading history...
96
            $give = $signature['give'] ?? 'void'
97
        );
98
99
        $method = $class->addMethod($name)
100
            ->setReturnNullable(str_starts_with($give, '?'))
101
            ->setReturnReference(str_starts_with($give, '&'))
102
            ->setReturnType($return)
103
            ->setPublic();
104
105
        if (!$class->isInterface()) {
106
            $method->setBody($this->getMethodBody($call, $pass, $give));
107
        }
108
109
        $params = ($take = $signature['take'] ?? false)
110
            ? explode(', ', $take)
111
            : [];
112
113
        foreach ($params as $param) {
114
            $this->addParameter($method, $param);
115
        }
116
117
        if ('$this' === $give) {
118
            $method->addComment('@return ' . '$this');
119
        }
120
    }
121
122
    protected function getClassFqn(): string
123
    {
124
        return $this->namespace . '\\' . $this->class;
125
    }
126
127
    protected function getMethodPassReplacements(): array
128
    {
129
        return [[], []];
130
    }
131
132
    protected function getMethodGiveReplacements(): array
133
    {
134
        return [[], []];
135
    }
136
137
    protected function getMethodBody(string $call, string $pass, string $give): string
138
    {
139
        $action = sprintf('$this->%s->%s(%s);', static::CORE, $call, $pass);
140
141
        return ('void' === $give) ? $action : 'return ' . $action;
142
    }
143
144
    protected function addParameter(Method $method, string $param): void
145
    {
146
        $parts = explode(' ', $param);
147
148
        $swap = $this->getParameterTypeReplacements();
149
        $type = str_replace(
150
            [...$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

150
            /** @scrutinizer ignore-type */ [...$swap[0], ...$strip = ['*']],
Loading history...
151
            [...$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

151
            /** @scrutinizer ignore-type */ [...$swap[1], ...$this->mapSymbols($strip)],
Loading history...
152
            $parts[0]
153
        );
154
155
        $swap = $this->getParameterNameReplacements();
156
        $name = str_replace(
157
            [...$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

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