Test Failed
Push — master ( 981043...9eb8e9 )
by Vitaly
04:13
created

Generator::endfunction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 2
Metric Value
c 3
b 0
f 2
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
//[PHPCOMPRESSOR(remove,start)]
3
namespace samsonphp\generator;
4
5
class Generator
6
{
7
8
    /** Single quote for string value **/
9
    const QUOTE_SINGLE = "'";
10
11
    /** Double quote for string value **/
12
    const QUOTE_DOUBLE = '"';
13
14
    /** @var string Generated code */
15
    public $code = '';
16
17
    /** @var integer Level of code line tabbing for new lines */
18
    public $tabs = 0;
19
20
    /** @var string Current class name */
21
    public $class;
22
23
    /**
24
     * Add simple text to current code position
25
     * @param string $text Text to add
26
     * @return self
27
     */
28
    public function text($text = '')
29
    {
30
        $this->code .= $text;
31
32
        return $this;
33
    }
34
35
    /**
36
     * Add current tabbing level to current line.
37
     *
38
     * @param string $endText Text to add after tabs
39
     * @param integer $tabs Amount of tabs to add
40
     * @param string $startText Text to add before tabs
41
     * @return Generator Chaining
42
     */
43
    public function tabs($endText = '', $tabs = null, $startText = '')
44
    {
45
        // Generate tabs array
46
        $tabs = isset($tabs) ? array_fill(0, $tabs, "\t") : array();
47
48
        // Add necessary amount of tabs to line and append text
49
        $this->text($startText.implode('', $tabs) . $endText);
50
51
        return $this;
52
    }
53
54
    /**
55
     * Add new line to code.
56
     *
57
     * @param string $text Code to add to new line
58
     * @param integer $tabs Tabs count
59
     * @return self
60
     */
61
    public function newline($text = '', $tabs = null)
62
    {
63
        // If no tabs count is specified set default tabs
64
        if (!isset($tabs)) {
65
            $tabs = $this->tabs;
66
        }
67
68
        return $this->tabs($text, $tabs, "\n");
69
    }
70
71
    /**
72
     * Add single line comment to code
73
     * @param string $text Comment text
74
     * @return self Chaining
75
     */
76
    public function comment($text = '')
77
    {
78
        return isset($text{0}) ? $this->newline("// " . $text) : $this;
79
    }
80
81
    /**
82
     * Add multi-line comment. If array with one line is passed
83
     * we create special syntax comment in one line, usually
84
     * used for class variable definition in more compact form.
85
     *
86
     * @param array $lines Array of comments lines
87
     * @return self Chaining
88
     */
89
    public function multicomment(array $lines = array())
90
    {
91
        // If array is not empty
92
        if (sizeof($lines)) {
93
            $this->newline("/**");
94
95
            // Multi-comment with single line
96
            if (sizeof($lines) === 1) {
97
                $this->text(' '.$lines[0].' */');
98
            } else { // Iterate comments lines and if comment line is not empty
99
                foreach ($lines as $line) {
100
                    if (isset($line{0})) {
101
                        $this->newline(" * " . $line);
102
                    }
103
                }
104
105
                return $this->newline(" */");
106
            }
107
108
        } else {
109
            return $this;
110
        }
111
    }
112
113
    /**
114
     * Add string value definition
115
     * @param string $value String value to add
116
     * @param string $tabs Tabs count
117
     * @param string $quote Type of quote
118
     * @return self
119
     */
120
    public function stringvalue($value, $tabs = null, $quote = self::QUOTE_SINGLE)
121
    {
122
        return $this->tabs($quote . $value . $quote, $tabs);
123
    }
124
125
    /**
126
     * Add array values definition
127
     * @param array $items Array key-value pairs collection
128
     * @return self Chaining
129
     */
130
    public function arrayvalue(array $items = array())
131
    {
132
        $this->text('array(');
133
        $this->tabs++;
134
135
        /*
136
        // TODO: Add array key-value выравнивание
137
         *
138
        // Determine largest key
139
        // Convert array to array of key lengths
140
        $lengths = array_map('strlen', array_keys($items));
141
        // Get lergest element
142
        $maxLength = max( $lengths );
143
        // Find largest position
144
        $key = array_search( $maxLength, $lengths );        
145
        $tab_size = 3;
146
        $tabs = round($maxLength / $tab_size);
147
        */
148
149
        // Iterate array items
150
        foreach ($items as $key => $value) {
151
            // Start array key definition
152
            $this->newline()->stringvalue($key, 2)->tabs('=>', 1);
153
154
            // If item value is array - recursion
155
            if (is_array($value)) $this->arrayvalue($value)->text(',');
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
156
            // Output value
157
            else $this->stringvalue($value, 1)->text(',');
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
158
        }
159
160
        $this->newline(')');
161
        $this->tabs--;
162
163
        return $this;
164
    }
165
166
    /**
167
     * Add variable definition with array merging.
168
     *
169
     * @param string $name Variable name
170
     * @param array $value Array of key-value items for merging it to other array
171
     * @param string $arrayName Name of array to merge to, if no is specified - $name is used
172
     * @return self Chaining
173
     */
174
    public function defarraymerge($name, array $value, $arrayName = null)
175
    {
176
        // If no other array is specified - set it to current
177
        if (!isset($arrayName)) {
178
            $arrayName = $name;
179
        }
180
181
        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...
182
    }
183
184
    /**
185
     * Add variable definition.
186
     *
187
     * @param string $name Variable name
188
     * @param string $value Variable default value
189
     * @param string $after String to insert after variable definition
190
     * @param string $end Closing part of variable definition
191
     * @param string $quote Type of quote
192
     * @return Generator Chaining
193
     */
194
    public function defVar($name, $value = null, $after = ' = ', $end = ';', $quote = self::QUOTE_SINGLE)
195
    {
196
        // Output variable definition
197
        $this->newline($name);
198
199
        $t = gettype($value);
0 ignored issues
show
Unused Code introduced by
$t is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
200
201
        // Get variable type
202
        switch (gettype($value)) {
203
            case 'integer':
204
            case 'boolean':
205
            case 'double':
206
                $this->text($after)->text($value)->text($end);
207
                break;
208
            case 'string':
209
                $this->text($after)->stringvalue($value, 0, $quote)->text($end);
210
                break;
211
            case 'array':
212
                $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...
213
                break;
214
            case 'NULL':
215
            case 'object':
216
            case 'resource':
217
            default:
218
                $this->text(';');
219
        }
220
221
        return $this;
222
    }
223
224
    /**
225
     * Add class definition.
226
     *
227
     * @param string $name Class name
228
     * @param string $extends Parent class name
229
     * @param array $implements Interfaces names collection
230
     * @return self Chaining
231
     */
232
    public function defClass($name, $extends = null, array $implements = array())
233
    {
234
        // If we define another class, and we were in other class context
235
        if (isset($this->class) && ($name !== $this->class)) {
236
            // Close old class context
237
            $this->endclass();
238
        }
239
240
        // Save new class name
241
        $this->class = $name;
242
243
        // Class definition start
244
        $this->newline('class ' . $name);
245
246
        // Parent class definition
247
        if (isset($extends)) {
248
            $this->text(' extends ' . $extends);
249
        }
250
251
        // Interfaces
252
        if (sizeof($implements)) {
253
            $this->text(' implements ' . implode(',', $implements));
254
        }
255
256
        $this->newline('{');
257
258
        $this->tabs++;
259
260
        return $this;
261
    }
262
263
    /**
264
     * Close current class context.
265
     *
266
     * @return self Chaining
267
     */
268
    public function endclass()
269
    {
270
        // Close class definition
271
        $this->newline('}')
272
            // Add one empty line after class definition
273
        ->newline('');
274
275
        $this->tabs--;
276
277
        return $this;
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|null $comment Variable description
286
     * @param string $value Variable default value
287
     * @return self Chaining
288
     */
289
    public function defClassVar($name, $visibility = 'public', $comment = null, $value = null)
290
    {
291
        if (isset($comment)) {
292
            $this->multicomment(array($comment));
293
        }
294
295
        return $this->defvar($visibility . ' ' . $name, $value)->newline();
296
    }
297
298
    /**
299
     * Add class constant definition.
300
     *
301
     * @param string $name Constant name
302
     * @param string $value Variable default value
303
     * @param string|null $comment Variable description
304
     * @return self Chaining
305
     */
306
    public function defClassConst($name, $value, $comment = null)
307
    {
308
        return $this->defClassVar(strtoupper($name), 'const', $comment, $value);
309
    }
310
311
    /**
312
     * Write file to disk
313
     * @param string $name Path to file
314
     * @param string $format Output file format
315
     */
316
    public function write($name, $format = 'php')
317
    {
318
        $code = $this->flush();
319
320
        if ($format == 'php') $code = '<?php ' . $code;
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
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
     * @param string $name Function name
345
     * @return self Chaining
346
     */
347
    public function deffunction($name)
348
    {
349
        return $this->newline('function ' . $name . '()')
350
            ->newline('{')
351
            ->tabs('', 1);
352
    }
353
354
    /**
355
     * Close current function context
356
     * @return\samson\activerecord\Generator
357
     */
358
    public function endfunction()
359
    {
360
        return $this->newline('}')->newline('');
361
    }
362
363
    /**
364
     * Constructor
365
     * @param string $namespace Code namespace
366
     */
367
    public function __construct($namespace = null)
368
    {
369
        // If namespace is defined - set it
370
        if (isset($namespace)) $this->defnamespace($namespace);
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
371
    }
372
373
    /**
374
     * Add namespace declaration
375
     * @param string $name Namespace name
376
     * @return self
377
     */
378
    private function defnamespace($name)
379
    {
380
        return $this->newline('namespace ' . $name . ';')->newline();
381
    }
382
383
}
384
//[PHPCOMPRESSOR(remove,end)]
385