Passed
Push — master ( 936362...6ffeb7 )
by Vitaly
02:35
created

Generator::defNamespace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

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

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...
216
                break;
217
            case 'string':
218
                $this->text($after)->stringValue($value, 0, $quote)->text($end);
219
                break;
220
            case 'array':
221
                $this->text($after)->arrayValue($value)->text($end);
222
                break;
223
            case 'NULL':
224
            case 'object':
225
            case 'resource':
226
            default:
227
                $this->text(';');
228
        }
229
230
        return $this;
231
    }
232
233
    /**
234
     * Add class definition.
235
     *
236
     * @param string $name Class name
237
     * @param string $extends Parent class name
238
     * @param array $implements Interfaces names collection
239
     * @return self Chaining
240
     */
241
    public function defClass($name, $extends = null, array $implements = array())
242
    {
243
        // If we define another class, and we were in other class context
244
        if (isset($this->class) && ($name !== $this->class)) {
245
            // Close old class context
246
            $this->endClass();
247
        }
248
249
        // Save new class name
250
        $this->class = $name;
251
252
        // Class definition start
253
        $this->newLine('class ' . $name);
254
255
        // Parent class definition
256
        if (isset($extends)) {
257
            $this->text(' extends ' . $extends);
258
        }
259
260
        // Interfaces
261
        if (sizeof($implements)) {
262
            $this->text(' implements ' . implode(',', $implements));
263
        }
264
265
        $this->newLine('{');
266
267
        $this->tabs++;
268
269
        return $this;
270
    }
271
272
    /**
273
     * Close current class context.
274
     *
275
     * @return self Chaining
276
     */
277
    public function endClass()
278
    {
279
        $this->tabs--;
280
281
        // Close class definition
282
        return $this->newLine('}')
283
            // Add one empty line after class definition
284
        ->newLine('');
285
    }
286
287
    /**
288
     * Define if statement condition.
289
     *
290
     * @param string $condition Condition statement
291
     * @return self Chaining
292
     */
293
    public function defIfCondition($condition)
294
    {
295
        $this->ifConditionLevel++;
296
297
        // Class definition start
298
        $this->newLine('if (' . $condition . ') {');
299
        $this->tabs++;
300
        return $this;
301
    }
302
303
    /**
304
     * Define elseif statement condition.
305
     *
306
     * @param string $condition Condition statement
307
     * @return self Chaining
308
     */
309
    public function defElseIfCondition($condition)
310
    {
311
        $this->tabs--;
312
        // Class definition start
313
        $this->newLine('} elseif (' . $condition . ') {');
314
        $this->tabs++;
315
        return $this;
316
    }
317
318
    /**
319
     * Define else statement.
320
     *
321
     * @return self Chaining
322
     */
323
    public function defElseCondition()
324
    {
325
        $this->tabs--;
326
        // Class definition start
327
        $this->newLine('} else {');
328
        $this->tabs++;
329
        return $this;
330
    }
331
332
    /**
333
     * Close if condition statement.
334
     *
335
     * @return self Chaining
336
     */
337
    public function endIfCondition()
338
    {
339
        if ($this->ifConditionLevel--) {
340
            $this->tabs--;
341
342
            // Close class definition
343
            return $this->newLine('}');
344
        }
345
346
        return $this;
347
    }
348
349
    /**
350
     * Add class variable definition.
351
     *
352
     * @param string $name Variable name
353
     * @param string $visibility Variable accessibility level
354
     * @param string $value Variable default value
355
     * @return self Chaining
356
     */
357
    public function defClassVar($name, $visibility = 'public', $value = null)
358
    {
359
        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...
360
            $this->multiComment(array($comment));
361
        }
362
363
        return $this->defvar($visibility . ' ' . $name, $value)->newLine();
364
    }
365
366
    /**
367
     * Add class constant definition.
368
     *
369
     * @param string $name Constant name
370
     * @param string $value Variable default value
371
     * @return self Chaining
372
     */
373
    public function defClassConst($name, $value)
374
    {
375
        return $this->defClassVar(strtoupper($name), 'const', $value);
376
    }
377
378
    /**
379
     * Write file to disk
380
     * @param string $name Path to file
381
     * @param string $format Output file format
382
     */
383
    public function write($name, $format = 'php')
384
    {
385
        $code = $this->flush();
386
387
        if ($format === 'php') {
388
            $code = '<?php ' . $code;
389
        }
390
391
        file_put_contents($name, $code, 0775);
392
    }
393
394
    /**
395
     * Flush internal data and return it.
396
     *
397
     * @return string Current generated code
398
     */
399
    public function flush()
400
    {
401
        // We should use 4 spaces instead of tabs
402
        $code = str_replace("\t", '    ', $this->code);
403
404
        $this->tabs = 0;
405
        $this->code = '';
406
        $this->class = null;
407
408
        return $code;
409
    }
410
411
    /**
412
     * Add function definition.
413
     *
414
     * @param string $name Function name
415
     * @param array $parameters Collection of parameters $typeHint => $paramName
416
     * @return Generator Chaining
417
     */
418
    public function defFunction($name, $parameters = array())
419
    {
420
        // Convert parameters to string
421
        $parameterList = array();
422
        foreach ($parameters as $type => $parameter) {
423
            $parameterList[] = (is_string($type) ? $type.' ' : '') . $parameter;
424
        }
425
        $parameterList = sizeof($parameterList) ? implode(', ', $parameterList) : '';
426
427
        $this->newLine('function ' . $name . '('.$parameterList.')')
428
            ->newLine('{')
429
            ->tabs('');
430
431
        $this->tabs++;
432
433
        return $this;
434
    }
435
436
    /**
437
     * Close current function context.
438
     *
439
     * @return self Chaining
440
     */
441
    public function endFunction()
442
    {
443
        $this->tabs--;
444
445
        return $this->newLine('}')->newLine('');
446
    }
447
448
    /**
449
     * Constructor
450
     * @param string $namespace Code namespace
451
     */
452
    public function __construct($namespace = null)
453
    {
454
        // If namespace is defined - set it
455
        if (isset($namespace)) {
456
            $this->defnamespace($namespace);
457
        }
458
    }
459
460
    /**
461
     * Add namespace declaration
462
     * @param string $name Namespace name
463
     * @return self
464
     */
465
    public function defNamespace($name)
466
    {
467
        return $this->newLine('namespace ' . $name . ';')->newLine();
468
    }
469
}
470
//[PHPCOMPRESSOR(remove,end)]
471