Test Failed
Push — master ( 11a060...c3fdcf )
by Vitaly
03:01
created

Generator::multiComment()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 23
rs 8.5907
cc 5
eloc 11
nc 5
nop 1
1
<?php
2
//[PHPCOMPRESSOR(remove,start)]
3
namespace samsonphp\generator;
4
5
class Generator
6
{
7
    /** Single quote for string value **/
8
    const QUOTE_SINGLE = "'";
9
10
    /** Double quote for string value **/
11
    const QUOTE_DOUBLE = '"';
12
13
    /** @var string Generated code */
14
    public $code = '';
15
16
    /** @var integer Level of code line tabbing for new lines */
17
    public $tabs = 0;
18
19
    /** @var string Current class name */
20
    public $class;
21
22
    /**
23
     * Add simple text to current code position
24
     * @param string $text Text to add
25
     * @return self
26
     */
27
    public function text($text = '')
28
    {
29
        $this->code .= $text;
30
31
        return $this;
32
    }
33
34
    /**
35
     * Add current tabbing level to current line.
36
     *
37
     * @param string $endText Text to add after tabs
38
     * @param integer $tabs Amount of tabs to add
39
     * @param string $startText Text to add before tabs
40
     * @return Generator Chaining
41
     */
42
    public function tabs($endText = '', $tabs = null, $startText = '')
43
    {
44
        // Generate tabs array
45
        $tabs = isset($tabs) ? array_fill(0, $tabs, "\t") : array();
46
47
        // Add necessary amount of tabs to line and append text
48
        $this->text($startText.implode('', $tabs) . $endText);
49
50
        return $this;
51
    }
52
53
    /**
54
     * Add new line to code.
55
     *
56
     * @param string $text Code to add to new line
57
     * @param integer $tabs Tabs count
58
     * @return self
59
     */
60
    public function newLine($text = '', $tabs = null)
61
    {
62
        // If no tabs count is specified set default tabs
63
        if (!isset($tabs)) {
64
            $tabs = $this->tabs;
65
        }
66
67
        return $this->tabs($text, $tabs, "\n");
68
    }
69
70
    /**
71
     * Add single line comment to code
72
     * @param string $text Comment text
73
     * @return self Chaining
74
     */
75
    public function comment($text = '')
76
    {
77
        return isset($text{0}) ? $this->newLine("// " . $text) : $this;
78
    }
79
80
    /**
81
     * Add multi-line comment. If array with one line is passed
82
     * we create special syntax comment in one line, usually
83
     * used for class variable definition in more compact form.
84
     *
85
     * @param array $lines Array of comments lines
86
     * @return self Chaining
87
     */
88
    public function multiComment(array $lines = array())
89
    {
90
        // If array is not empty
91
        if (sizeof($lines)) {
92
            $this->newLine("/**");
93
94
            // Multi-comment with single line
95
            if (sizeof($lines) === 1) {
96
                $this->text(' '.$lines[0].' */');
97
            } else { // Iterate comments lines and if comment line is not empty
98
                foreach ($lines as $line) {
99
                    if (isset($line{0})) {
100
                        $this->newLine(" * " . $line);
101
                    }
102
                }
103
104
                return $this->newLine(" */");
105
            }
106
107
        }
108
109
        return $this;
110
    }
111
112
    /**
113
     * Add one line variable definition comment.
114
     *
115
     * @param string $type Variable type
116
     * @param string $description Variable description
117
     * @param string $name Variable name
118
     * @return self Chaining
119
     */
120
    public function commentVar($type, $description, $name = '')
121
    {
122
        return $this->multiComment(array(
123
            '@var ' . trim($type) . (isset($name) ? trim($name) . ' ' : ' ') . trim($description)
124
        ));
125
    }
126
127
    /**
128
     * Add string value definition.
129
     *
130
     * @param string $value String value to add
131
     * @param string $tabs Tabs count
132
     * @param string $quote Type of quote
133
     * @return self Chaining
134
     */
135
    public function stringValue($value, $tabs = null, $quote = self::QUOTE_SINGLE)
136
    {
137
        return $this->tabs($quote . $value . $quote, $tabs);
138
    }
139
140
    /**
141
     * Add array values definition.
142
     *
143
     * @param array $items Array key-value pairs collection
144
     * @return self Chaining
145
     */
146
    public function arrayValue(array $items = array())
147
    {
148
        $this->text('array(');
149
        $this->tabs++;
150
151
        // Iterate array items
152
        foreach ($items as $key => $value) {
153
            // Start array key definition
154
            $this->newLine()->stringValue($key)->text(' => ');
155
156
            // If item value is array - recursion
157
            if (is_array($value)) {
158
                $this->arrayValue($value)->text(',');
159
            } else {
160
                $this->stringValue($value)->text(',');
161
            }
162
        }
163
164
        $this->tabs--;
165
        $this->newLine(')');
166
167
        return $this;
168
    }
169
170
    /**
171
     * Add variable definition with array merging.
172
     *
173
     * @param string $name Variable name
174
     * @param array $value Array of key-value items for merging it to other array
175
     * @param string $arrayName Name of array to merge to, if no is specified - $name is used
176
     * @return self Chaining
177
     */
178
    public function defArrayMerge($name, array $value, $arrayName = null)
179
    {
180
        // If no other array is specified - set it to current
181
        if (!isset($arrayName)) {
182
            $arrayName = $name;
183
        }
184
185
        return $this->defvar($name, $value, ' = array_merge( ' . $arrayName . ', ', '')->text(');');
0 ignored issues
show
Documentation introduced by
$value is of type array, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
186
    }
187
188
    /**
189
     * Add variable definition.
190
     *
191
     * @param string $name Variable name
192
     * @param string $value Variable default value
193
     * @param string $after String to insert after variable definition
194
     * @param string $end Closing part of variable definition
195
     * @param string $quote Type of quote
196
     * @return Generator Chaining
197
     */
198
    public function defVar($name, $value = null, $after = ' = ', $end = ';', $quote = self::QUOTE_SINGLE)
199
    {
200
        // Output variable definition
201
        $this->newLine($name);
202
203
        // Get variable type
204
        switch (gettype($value)) {
205
            case 'integer':
206
            case 'boolean':
207
            case 'double':
208
                $this->text($after)->text($value)->text($end);
209
                break;
210
            case 'string':
211
                $this->text($after)->stringValue($value, 0, $quote)->text($end);
212
                break;
213
            case 'array':
214
                $this->text($after)->arrayValue($value)->text($end);
0 ignored issues
show
Documentation introduced by
$value is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
215
                break;
216
            case 'NULL':
217
            case 'object':
218
            case 'resource':
219
            default:
220
                $this->text(';');
221
        }
222
223
        return $this;
224
    }
225
226
    /**
227
     * Add class definition.
228
     *
229
     * @param string $name Class name
230
     * @param string $extends Parent class name
231
     * @param array $implements Interfaces names collection
232
     * @return self Chaining
233
     */
234
    public function defClass($name, $extends = null, array $implements = array())
235
    {
236
        // If we define another class, and we were in other class context
237
        if (isset($this->class) && ($name !== $this->class)) {
238
            // Close old class context
239
            $this->endClass();
240
        }
241
242
        // Save new class name
243
        $this->class = $name;
244
245
        // Class definition start
246
        $this->newLine('class ' . $name);
247
248
        // Parent class definition
249
        if (isset($extends)) {
250
            $this->text(' extends ' . $extends);
251
        }
252
253
        // Interfaces
254
        if (sizeof($implements)) {
255
            $this->text(' implements ' . implode(',', $implements));
256
        }
257
258
        $this->newLine('{');
259
260
        $this->tabs++;
261
262
        return $this;
263
    }
264
265
    /**
266
     * Close current class context.
267
     *
268
     * @return self Chaining
269
     */
270
    public function endClass()
271
    {
272
        $this->tabs--;
273
274
        // Close class definition
275
        return $this->newLine('}')
276
            // Add one empty line after class definition
277
        ->newLine('');
278
    }
279
280
    /**
281
     * Add class variable definition.
282
     *
283
     * @param string $name Variable name
284
     * @param string $visibility Variable accessibility level
285
     * @param string $value Variable default value
286
     * @return self Chaining
287
     */
288
    public function defClassVar($name, $visibility = 'public', $value = null)
289
    {
290
        if (isset($comment) && isset($comment{0})) {
0 ignored issues
show
Bug introduced by
The variable $comment seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
291
            $this->multiComment(array($comment));
292
        }
293
294
        return $this->defvar($visibility . ' ' . $name, $value)->newLine();
295
    }
296
297
    /**
298
     * Add class constant definition.
299
     *
300
     * @param string $name Constant name
301
     * @param string $value Variable default value
302
     * @return self Chaining
303
     */
304
    public function defClassConst($name, $value)
305
    {
306
        return $this->defClassVar(strtoupper($name), 'const', $value);
307
    }
308
309
    /**
310
     * Write file to disk
311
     * @param string $name Path to file
312
     * @param string $format Output file format
313
     */
314
    public function write($name, $format = 'php')
315
    {
316
        $code = $this->flush();
317
318
        if ($format === 'php') {
319
            $code = '<?php ' . $code;
320
        }
321
322
        file_put_contents($name, $code, 0775);
323
    }
324
325
    /**
326
     * Flush internal data and return it.
327
     *
328
     * @return string Current generated code
329
     */
330
    public function flush()
331
    {
332
        // We should use 4 spaces instead of tabs
333
        $code = str_replace("\t", '    ', $this->code);
334
335
        $this->tabs = 0;
336
        $this->code = '';
337
        $this->class = null;
338
339
        return $code;
340
    }
341
342
    /**
343
     * Add function definition.
344
     *
345
     * @param string $name Function name
346
     * @param array $parameters Collection of parameters $typeHint => $paramName
347
     * @return Generator Chaining
348
     */
349
    public function defFunction($name, $parameters = array())
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
350
    {
351
        // Convert parameters to string
352
        $parameterList = array();
353
        foreach ($parameters as $type => $name) {
354
            $parameterList[] = (is_string($type) ? $type.' ' : '') . $name;
355
        }
356
        $parameterList = implode(', ', $parameterList);
357
358
        $this->newLine('function ' . $name . '('.$parameterList.')')
359
            ->newLine('{')
360
            ->tabs('');
361
362
        $this->tabs++;
363
364
        return $this;
365
    }
366
367
    /**
368
     * Close current function context.
369
     *
370
     * @return self Chaining
371
     */
372
    public function endFunction()
373
    {
374
        $this->tabs--;
375
376
        return $this->newLine('}')->newLine('');
377
    }
378
379
    /**
380
     * Constructor
381
     * @param string $namespace Code namespace
382
     */
383
    public function __construct($namespace = null)
384
    {
385
        // If namespace is defined - set it
386
        if (isset($namespace)) {
387
            $this->defnamespace($namespace);
388
        }
389
    }
390
391
    /**
392
     * Add namespace declaration
393
     * @param string $name Namespace name
394
     * @return self
395
     */
396
    private function defnamespace($name)
397
    {
398
        return $this->newLine('namespace ' . $name . ';')->newLine();
399
    }
400
}
401
//[PHPCOMPRESSOR(remove,end)]
402