ConfigurationGenerator::codeEnd()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
/*
4
 * This file is part of the ConfigCacheBundle package.
5
 *
6
 * Copyright (c) 2015-2016 Yahoo Japan Corporation
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace YahooJapan\ConfigCacheBundle\Command;
13
14
use Symfony\Component\HttpKernel\Bundle\Bundle;
15
16
/**
17
 * ConfigurationGenerator generates a code sample of Configuration class.
18
 */
19
class ConfigurationGenerator
20
{
21
    protected $iterator;
22
    protected $queue;
23
    protected $bundle;
24
    protected $className;
25
    protected $namespace;
26
    protected $rootKey;
27
    protected $width = 4;
28
    protected $previousDepth = -1;
29
30
    /**
31
     * Constructor.
32
     *
33
     * @param array  $config
34
     * @param string $className
35
     */
36 3
    public function __construct(array $config, Bundle $bundle, $className = 'Configuration')
37
    {
38 3
        $this->bundle    = $bundle;
39 3
        $this->className = $className;
40
41 3
        $this->initialize($config);
42 3
    }
43
44
    /**
45
     * Generates a Configuration file.
46
     *
47
     * @return string
48
     */
49 4
    public function generate()
50
    {
51 4
        if (!$this->initialized()) {
52 1
            throw new \LogicException('The bundle is not initialized.');
53
        }
54
55 3
        foreach ($this->iterator as $key => $node) {
56
            // add children, end, arrayNode, and scalarNode
57 3
            $this->addArrayNodeOnAndOff()->addNodes($key, $node);
58 3
            $this->previousDepth = $this->iterator->getDepth();
59 3
        }
60
61
        // post process
62 3
        $this->postIteration();
63
64 3
        return $this->generateConfiguration();
65
    }
66
67
    /**
68
     * Initializes iterator, namespace, rootKey to generate.
69
     *
70
     * @param array $config
71
     */
72 3
    protected function initialize(array $config)
73
    {
74 3
        $this->iterator  = $this->createIterator($config);
75 3
        $this->queue     = $this->createQueue();
76 3
        $this->namespace = $this->bundle->getNamespace();
77 3
        $this->rootKey   = $this->bundle->getContainerExtension()->getAlias();
78 3
    }
79
80
    /**
81
     * Whether the ConfigurationGenerator is initialized or not.
82
     *
83
     * @return bool
84
     */
85 4
    protected function initialized()
86
    {
87 4
        return !is_null($this->bundle) && !is_null($this->namespace) && !is_null($this->rootKey);
88
    }
89
90
    /**
91
     * Adds an arrayNode start and end code.
92
     *
93
     * adds arrayNode start/end(children(), end())
94
     *
95
     * @return ConfigurationGenerator
96
     */
97 3
    protected function addArrayNodeOnAndOff()
98
    {
99 3
        $currentDepth = $this->iterator->getDepth();
100
101
        // start iteration
102 3
        if ($this->previousDepth === -1) {
103 3
            $this->queue->enqueue($this->codeChildren($this->width));
104
105
        // forward into leaf(max one operation)
106 3
        } elseif ($this->previousDepth < $currentDepth) {
107 3
            $this->queue->enqueue($this->codeChildren($this->getIndentCount()));
108
109
        // forward into root(one or more operation)
110 3
        } else {
111 2
            $this->codeEndByCurrentDepth($currentDepth);
112
        }
113
114 3
        return $this;
115
    }
116
117
    /**
118
     * Adds an arrayNode or a scalarNode.
119
     *
120
     * @param string $key
121
     * @param mixed  $node
122
     *
123
     * @return ConfigurationGenerator
124
     */
125 3
    protected function addNodes($key, $node)
126
    {
127 3
        $indent = $this->getIndentCount();
128
129 3
        if ($this->iterator->callHasChildren()) {
130 3
            if ($node !== array()) {
131 3
                $code = $this->codeArrayNode($indent + $this->width, $key);
132 3
            } else {
133 2
                $code = $this->codeArrayNodeWithPrototype($indent + $this->width, $key);
134
            }
135 3
            $this->queue->enqueue($code);
136 3
        } else {
137 3
            $this->queue->enqueue($this->codeScalarNode($indent + $this->width, $key));
138
        }
139
140 3
        return $this;
141
    }
142
143
    /**
144
     * Post iteration process to add a last end() and a semicolon.
145
     */
146 3
    protected function postIteration()
147
    {
148 3
        $this->codeEndByCurrentDepth(0);
149 3
        $this->queue->enqueue($this->codeEnd($this->width));
150 3
        $this->queue->enqueue($this->codeSemicolon($this->width));
151 3
    }
152
153
    /**
154
     * Generates a Configuration file string.
155
     *
156
     * @return string
157
     */
158 3
    protected function generateConfiguration()
159
    {
160
        $configuration = <<<CONFIGURATION_PREFIX
161
<?php
162
163 3
namespace $this->namespace\DependencyInjection;
164
165
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
166
use Symfony\Component\Config\Definition\ConfigurationInterface;
167
168
/**
169
 * This is the class that validates and merges configuration from your app/config files
170
 *
171
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
172
 */
173 3
class $this->className implements ConfigurationInterface
174
{
175
    /**
176
     * {@inheritdoc}
177
     */
178
    public function getConfigTreeBuilder()
179
    {
180
        \$treeBuilder = new TreeBuilder();
181 3
        \$rootNode    = \$treeBuilder->root('$this->rootKey');
182
CONFIGURATION_PREFIX
183 3
        .PHP_EOL;
184 3
        if (count($this->queue) > 0) {
185 3
            $configuration .= '        $rootNode'.PHP_EOL;
186 3
        }
187
188 3
        foreach ($this->queue as $code) {
189 3
            $configuration .= $code;
190 3
        }
191
192
        $configuration .= <<<'CONFIGURATION_SUFFIX'
193
194
        return $treeBuilder;
195
    }
196
}
197
CONFIGURATION_SUFFIX
198 3
        .PHP_EOL;
199
200 3
        return $configuration;
201
    }
202
203
    /**
204
     * Counts an indent and return indented.
205
     *
206
     * @param int $count
207
     *
208
     * @return string
209
     */
210 3
    protected function indent($count)
211
    {
212 3
        return str_repeat(' ', $count + $this->width * 2);
213
    }
214
215
    /**
216
     * Gets an indent count.
217
     *
218
     * @param int|null $depth
219
     *
220
     * @return int
221
     */
222 3
    protected function getIndentCount($depth = null)
223
    {
224 3
        $depth = is_null($depth) ? $this->iterator->getDepth() : $depth;
225
226 3
        return $depth * $this->width * 2 + $this->width;
227
    }
228
229
    /**
230
     * Codes a children().
231
     *
232
     * @param int $indent
233
     *
234
     * @return string
235
     */
236 3
    protected function codeChildren($indent)
237
    {
238 3
        return $this->indent($indent).'->children()'.PHP_EOL;
239
    }
240
241
    /**
242
     * Codes an end().
243
     *
244
     * @param int $indent
245
     *
246
     * @return string
247
     */
248 3
    protected function codeEnd($indent)
249
    {
250 3
        return $this->indent($indent).'->end()'.PHP_EOL;
251
    }
252
253
    /**
254
     * Codes end() by current depth.
255
     *
256
     * @param int $currentDepth
257
     */
258 3
    protected function codeEndByCurrentDepth($currentDepth)
259
    {
260 3
        for ($i = $this->previousDepth; $i > $currentDepth; $i--) {
261 3
            $innerIndent = $this->getIndentCount($i);
262 3
            $this->queue->enqueue($this->codeEnd($innerIndent));
263 3
            $this->queue->enqueue($this->codeEnd($innerIndent - $this->width));
264 3
        }
265 3
    }
266
267
    /**
268
     * Codes an arrayNode().
269
     *
270
     * @param int    $indent
271
     * @param string $key
272
     * @param string $addCodes
273
     *
274
     * @return string
275
     */
276 3
    protected function codeArrayNode($indent, $key, $addCodes = '')
277
    {
278 3
        $codes = array($this->indent($indent)."->arrayNode('{$key}')", $addCodes, PHP_EOL);
279
280 3
        return implode('', $codes);
281
    }
282
283
    /**
284
     * Codes an arrayNode() with prototype('scalar').
285
     *
286
     * @param int    $indent
287
     * @param string $key
288
     *
289
     * @return string
290
     */
291 2
    protected function codeArrayNodeWithPrototype($indent, $key)
292
    {
293 2
        return $this->codeArrayNode($indent, $key, "->prototype('scalar')->end()->end()");
294
    }
295
296
    /**
297
     * Codes an scalarNode().
298
     *
299
     * @param int    $indent
300
     * @param string $key
301
     *
302
     * @return string
303
     */
304 3
    protected function codeScalarNode($indent, $key)
305
    {
306 3
        return $this->indent($indent)."->scalarNode('{$key}')->end()".PHP_EOL;
307
    }
308
309
    /**
310
     * Codes an semicolon.
311
     *
312
     * @param int $indent
313
     *
314
     * @return string
315
     */
316 3
    protected function codeSemicolon($indent)
317
    {
318 3
        return $this->indent($indent).';'.PHP_EOL;
319
    }
320
321
    /**
322
     * Creates an outer iterator.
323
     *
324
     * @param array $config
325
     *
326
     * @return \RecursiveIteratorIterator
327
     */
328 3
    protected function createIterator(array $config)
329
    {
330 3
        $innerIterator = $this->createInnerIterator($config);
331
332 3
        return new \RecursiveIteratorIterator($innerIterator, \RecursiveIteratorIterator::SELF_FIRST);
333
    }
334
335
    /**
336
     * Creates an inner iterator.
337
     *
338
     * @param array $config
339
     *
340
     * @return \RecursiveArrayIterator
341
     */
342 3
    protected function createInnerIterator(array $config)
343
    {
344 3
        return new \RecursiveArrayIterator($config);
345
    }
346
347
    /**
348
     * Creates a queue.
349
     *
350
     * @return \SplQueue
351
     */
352 3
    protected function createQueue()
353
    {
354 3
        return new \SplQueue();
355
    }
356
}
357