Completed
Push — master ( ea9c95...7440d1 )
by Craig
08:36
created

ZikulaKernel::boot()   C

Complexity

Conditions 10
Paths 32

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 14
c 1
b 0
f 0
nc 32
nop 0
dl 0
loc 24
rs 5.2164

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Zikula package.
5
 *
6
 * Copyright Zikula Foundation - http://zikula.org/
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 Zikula\Bundle\CoreBundle\HttpKernel;
13
14
use Composer\Autoload\ClassLoader;
15
use Symfony\Component\Config\ConfigCache;
16
use Symfony\Component\Debug\DebugClassLoader;
17
use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder;
18
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
19
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
20
use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
21
use Symfony\Component\HttpKernel\Kernel;
22
use Symfony\Component\Yaml\Yaml;
23
use Zikula\Bridge\DependencyInjection\ContainerBuilder;
24
use Zikula\Bridge\DependencyInjection\PhpDumper;
25
use Zikula\Core\AbstractBundle;
26
use Zikula\Core\AbstractModule;
27
use Zikula\ThemeModule\AbstractTheme;
28
29
abstract class ZikulaKernel extends Kernel
30
{
31
    /**
32
     * @var boolean
33
     */
34
    private $dump = true;
35
36
    /**
37
     * @var array
38
     */
39
    private $modules = [];
40
41
    /**
42
     * @var array
43
     */
44
    private $moduleMap = [];
45
46
    /**
47
     * @var array
48
     */
49
    private $themes = [];
50
51
    /**
52
     * @var array
53
     */
54
    private $themeMap = [];
55
56
    /**
57
     * @var ClassLoader
58
     */
59
    private $autoloader;
60
61
    /**
62
     * Flag determines if container is dumped or not
63
     *
64
     * @param $flag
65
     */
66
    public function setDump($flag)
67
    {
68
        $this->dump = $flag;
69
    }
70
71
    public function boot()
72
    {
73
        if (null === $this->autoloader) {
74
            $this->getAutoloader();
75
        }
76
77
        parent::boot();
78
79
        foreach ($this->bundles as $name => $bundle) {
80
            if ($bundle instanceof AbstractModule && !isset($this->modules[$name])) {
81
                $this->modules[$name] = $bundle;
82
            } elseif ($bundle instanceof AbstractTheme && !isset($this->themes[$name])) {
83
                $this->themes[$name] = $bundle;
84
            }
85
        }
86
87
        foreach ($this->bundleMap as $name => $bundles) {
88
            if ($bundles[0] instanceof AbstractModule) {
89
                $this->moduleMap[$name] = $bundles;
90
            } elseif ($bundles[0] instanceof AbstractTheme) {
91
                $this->themeMap[$name] = $bundles;
92
            }
93
        }
94
    }
95
96
    /**
97
     * Get named module bundle.
98
     *
99
     * @param string  $moduleName
100
     * @param boolean $first
101
     *
102
     * @throws \InvalidArgumentException when the bundle is not enabled
103
     * @return \Zikula\Core\AbstractModule|\Zikula\Core\AbstractModule[]
104
     */
105 View Code Duplication
    public function getModule($moduleName, $first = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
    {
107
        if (!isset($this->moduleMap[$moduleName])) {
108
            throw new \InvalidArgumentException(sprintf('Module "%s" does not exist or it is not enabled.', $moduleName, get_class($this)));
109
        }
110
111
        if (true === $first) {
112
            return $this->moduleMap[$moduleName][0];
113
        }
114
115
        return $this->moduleMap[$moduleName];
116
    }
117
118
    public function getModules()
119
    {
120
        return $this->modules;
121
    }
122
123
    /**
124
     * Get named theme bundle.
125
     *
126
     * @param string  $themeName
127
     * @param boolean $first
128
     *
129
     * @throws \InvalidArgumentException when the bundle is not enabled
130
     *
131
     * @return AbstractTheme|AbstractTheme
132
     */
133 View Code Duplication
    public function getTheme($themeName, $first = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
134
    {
135
        if (!isset($this->themeMap[$themeName])) {
136
            throw new \InvalidArgumentException(sprintf('Theme "%s" does not exist or it is not enabled.', $themeName, get_class($this)));
137
        }
138
139
        if (true === $first) {
140
            return $this->themeMap[$themeName][0];
141
        }
142
143
        return $this->themeMap[$themeName];
144
    }
145
146
    public function getThemes()
147
    {
148
        return $this->themes;
149
    }
150
151
    public function getJustBundles()
152
    {
153
        $bundles = [];
154
        foreach ($this->bundles as $bundle) {
155
            if (!$bundle instanceof AbstractBundle) {
156
                $bundles[] = $bundle;
157
            }
158
        }
159
160
        return $bundles;
161
    }
162
163
    public function setAutoloader(ClassLoader $autoloader)
164
    {
165
        $this->autoloader = $autoloader;
166
    }
167
168
    public function getAutoloader()
169
    {
170
        if (null === $this->autoloader) {
171
            $loaders = spl_autoload_functions();
172
            if ($loaders[0][0] instanceof DebugClassLoader) {
173
                $classLoader = $loaders[0][0]->getClassLoader();
174
                if (is_callable($classLoader) && is_object($classLoader[0])) {
175
                    $this->autoloader = $classLoader[0];
176
                } elseif (is_object($classLoader)) {
177
                    $this->autoloader = $classLoader;
178
                }
179
            } else {
180
                $this->autoloader = $loaders[0][0];
181
            }
182
        }
183
184
        return $this->autoloader;
185
    }
186
187
    public function getConnectionConfig()
188
    {
189
        $config = Yaml::parse(file_get_contents($this->rootDir . '/config/parameters.yml'));
190 View Code Duplication
        if (is_readable($file = $this->rootDir . '/config/custom_parameters.yml')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
            $config = array_merge($config, Yaml::parse(file_get_contents($file)));
192
        }
193
194
        return $config;
195
    }
196
197
    public function isClassInBundle($class)
198
    {
199
        /* @var BundleInterface $bundle */
200
        foreach ($this->getBundles() as $bundle) {
201
            if (0 === strpos($class, $bundle->getNamespace())) {
202
                return $bundle instanceof AbstractBundle;
203
            }
204
        }
205
206
        return false;
207
    }
208
209
    /**
210
     * Initializes the data structures related to the bundle management.
211
     *
212
     *  - the bundles property maps a bundle name to the bundle instance,
213
     *  - the bundleMap property maps a bundle name to the bundle inheritance hierarchy (most derived bundle first).
214
     *
215
     * @throws \LogicException if two bundles share a common name
216
     * @throws \LogicException if a bundle tries to extend a non-registered bundle
217
     * @throws \LogicException if a bundle tries to extend itself
218
     * @throws \LogicException if two bundles extend the same ancestor
219
     */
220
    protected function initializeBundles()
221
    {
222
        // init bundles
223
        $this->bundles = [];
224
        $topMostBundles = [];
225
        $directChildren = [];
226
227
        foreach ($this->registerBundles() as $bundle) {
228
            $name = $bundle->getName();
229
            if (isset($this->bundles[$name])) {
230
                throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s"', $name));
231
            }
232
            $this->bundles[$name] = $bundle;
233
234
            if ($parentName = $bundle->getParent()) {
235
                if (isset($directChildren[$parentName])) {
236
                    throw new \LogicException(sprintf('Bundle "%s" is directly extended by two bundles "%s" and "%s".', $parentName, $name, $directChildren[$parentName]));
237
                }
238
                if ($parentName == $name) {
239
                    throw new \LogicException(sprintf('Bundle "%s" can not extend itself.', $name));
240
                }
241
                $directChildren[$parentName] = $name;
242
            } else {
243
                $topMostBundles[$name] = $bundle;
244
            }
245
        }
246
247
        // look for orphans
248
        if (count($diff = array_values(array_diff(array_keys($directChildren), array_keys($this->bundles))))) {
249
            throw new \LogicException(sprintf('Bundle "%s" extends bundle "%s", which is not registered.', $directChildren[$diff[0]], $diff[0]));
250
        }
251
252
        // inheritance
253
        $this->bundleMap = [];
254
        foreach ($topMostBundles as $name => $bundle) {
255
            $bundleMap = [$bundle];
256
            $hierarchy = [$name];
257
258
            while (isset($directChildren[$name])) {
259
                $name = $directChildren[$name];
260
                array_unshift($bundleMap, $this->bundles[$name]);
261
                $hierarchy[] = $name;
262
            }
263
264
            foreach ($hierarchy as $bundle) {
265
                $this->bundleMap[$bundle] = $bundleMap;
266
                array_pop($bundleMap);
267
            }
268
        }
269
    }
270
271
    /**
272
     * Initializes the service container.
273
     *
274
     * The cached version of the service container is used when fresh, otherwise the
275
     * container is built.
276
     *
277
     * Overridden not to dump the container.
278
     */
279
    protected function initializeContainer()
280
    {
281
        if (true === $this->dump) {
282
            return parent::initializeContainer();
283
        }
284
285
        $this->container = $this->buildContainer();
286
        $this->container->set('kernel', $this);
287
    }
288
289
    /**
290
     * Dumps the service container to PHP code in the cache.
291
     *
292
     * @param ConfigCache      $cache     The config cache
293
     * @param SymfonyContainerBuilder $container The service container
294
     * @param string           $class     The name of the class to generate
295
     * @param string           $baseClass The name of the container's base class
296
     */
297
    protected function dumpContainer(ConfigCache $cache, SymfonyContainerBuilder $container, $class, $baseClass)
298
    {
299
        // cache the container
300
        $dumper = new PhpDumper($container);
301
        $content = $dumper->dump(['class' => $class, 'base_class' => $baseClass]);
302
        if (!$this->debug) {
303
            $content = self::stripComments($content);
304
        }
305
306
        $cache->write($content, $container->getResources());
307
    }
308
309
    /**
310
     * Gets the container's base class.
311
     *
312
     * All names except Container must be fully qualified.
313
     *
314
     * Allows container to build services after being dumped and frozen
315
     *
316
     * @return string
317
     */
318
    protected function getContainerBaseClass()
319
    {
320
        //return 'Symfony\Component\DependencyInjection\Container';
321
        return 'Zikula\Bridge\DependencyInjection\ContainerBuilder';
322
    }
323
324
    /**
325
     * Gets a new ContainerBuilder instance used to build the service container.
326
     *
327
     * @return ContainerBuilder
328
     */
329
    protected function getContainerBuilder()
330
    {
331
        return new ContainerBuilder(new ParameterBag($this->getKernelParameters()));
332
    }
333
334
    /**
335
     * Gets the environment parameters.
336
     *
337
     * Only the parameters starting with "ZIKULA__" are considered.
338
     *
339
     * @return array An array of parameters
340
     */
341
    protected function getEnvParameters()
0 ignored issues
show
Coding Style introduced by
getEnvParameters uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
342
    {
343
        $parameters = parent::getEnvParameters();
344
        foreach ($_SERVER as $key => $value) {
345
            if (0 === strpos($key, 'ZIKULA__')) {
346
                $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
347
            }
348
        }
349
350
        return $parameters;
351
    }
352
353
    /**
354
     * Prepares the ContainerBuilder before it is compiled.
355
     *
356
     * @param SymfonyContainerBuilder $container A ContainerBuilder instance
357
     */
358
    protected function prepareContainer(SymfonyContainerBuilder $container)
359
    {
360
        $extensions = [];
361
        foreach ($this->bundles as $bundle) {
362
            if ($bundle instanceof AbstractBundle && $bundle->getState() != AbstractBundle::STATE_ACTIVE) {
363
                continue;
364
            }
365
            if ($extension = $bundle->getContainerExtension()) {
366
                $container->registerExtension($extension);
367
                $extensions[] = $extension->getAlias();
368
            }
369
370
            if ($this->debug) {
371
                $container->addObjectResource($bundle);
372
            }
373
        }
374
        foreach ($this->bundles as $bundle) {
375
            if ($bundle instanceof AbstractBundle && $bundle->getState() != AbstractBundle::STATE_ACTIVE) {
376
                continue;
377
            }
378
            $bundle->build($container);
379
        }
380
381
        // ensure these extensions are implicitly loaded
382
        $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));
383
    }
384
385
    /**
386
     * {@inheritdoc}
387
     *
388
     * @throws \RuntimeException if a custom resource is hidden by a resource in a derived bundle
389
     */
390
    public function locateResource($name, $dir = null, $first = true)
391
    {
392
        $themeBundle = $this->container->get('zikula_core.common.theme_engine')->getTheme();
393
        $locations = parent::locateResource($name, $dir, false);
394
        if ($locations && (false !== strpos($locations[0], $dir))) {
395
            // if found in $dir (typically app/Resources) return it immediately.
396
            return $locations[0];
397
        }
398
399
        // add theme path to template locator
400
        // this method functions if the controller uses `@Template` or `ZikulaSpecModule:Foo:index.html.twig` naming scheme
401
        // if `@ZikulaSpecModule/Foo/index.html.twig` (name-spaced) naming scheme is used
402
        // the \Zikula\Bundle\CoreBundle\EventListener\Theme\TemplatePathOverrideListener::setUpThemePathOverrides method is used instead
403
        if ($themeBundle && (false === strpos($name, $themeBundle->getName()))) {
404
            // do not add theme override path to theme files
405
            $customThemePath = $themeBundle->getPath() . '/Resources';
406
407
            return parent::locateResource($name, $customThemePath, true);
408
        }
409
410
        return $locations[0];
411
    }
412
}
413