Completed
Push — master ( e25986...ffddd1 )
by Craig
07:06
created

ZikulaKernel::setDump()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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
// Defines for access levels
30
define('ACCESS_INVALID', -1);
31
define('ACCESS_NONE', 0);
32
define('ACCESS_OVERVIEW', 100);
33
define('ACCESS_READ', 200);
34
define('ACCESS_COMMENT', 300);
35
define('ACCESS_MODERATE', 400);
36
define('ACCESS_EDIT', 500);
37
define('ACCESS_ADD', 600);
38
define('ACCESS_DELETE', 700);
39
define('ACCESS_ADMIN', 800);
40
41
abstract class ZikulaKernel extends Kernel implements ZikulaHttpKernelInterface
42
{
43
    const VERSION = '2.0.0';
44
45
    const VERSION_SUB = 'Concerto';
46
47
    const PHP_MINIMUM_VERSION = '5.5.9';
48
49
    /**
50
     * The parameter name identifying the currently installed version of the core.
51
     */
52
    const CORE_INSTALLED_VERSION_PARAM = 'core_installed_version';
53
54
    /**
55
     * Public list of core modules and their bundle class.
56
     * @var array
57
     */
58
    public static $coreModules = [
59
        'ZikulaAdminModule' => 'Zikula\AdminModule\ZikulaAdminModule',
60
        'ZikulaBlocksModule' => 'Zikula\BlocksModule\ZikulaBlocksModule',
61
        'ZikulaCategoriesModule' => 'Zikula\CategoriesModule\ZikulaCategoriesModule',
62
        'ZikulaExtensionsModule' => 'Zikula\ExtensionsModule\ZikulaExtensionsModule',
63
        'ZikulaGroupsModule' => 'Zikula\GroupsModule\ZikulaGroupsModule',
64
        'ZikulaMailerModule' => 'Zikula\MailerModule\ZikulaMailerModule',
65
        'ZikulaPermissionsModule' => 'Zikula\PermissionsModule\ZikulaPermissionsModule',
66
        'ZikulaRoutesModule' => 'Zikula\RoutesModule\ZikulaRoutesModule',
67
        'ZikulaSearchModule' => 'Zikula\SearchModule\ZikulaSearchModule',
68
        'ZikulaSecurityCenterModule' => 'Zikula\SecurityCenterModule\ZikulaSecurityCenterModule',
69
        'ZikulaSettingsModule' => 'Zikula\SettingsModule\ZikulaSettingsModule',
70
        'ZikulaThemeModule' => 'Zikula\ThemeModule\ZikulaThemeModule',
71
        'ZikulaUsersModule' => 'Zikula\UsersModule\ZikulaUsersModule',
72
        'ZikulaZAuthModule' => 'Zikula\ZAuthModule\ZikulaZAuthModule',
73
        'ZikulaMenuModule' => 'Zikula\MenuModule\ZikulaMenuModule',
74
    ];
75
76
    /**
77
     * @var boolean
78
     */
79
    private $dump = true;
80
81
    /**
82
     * @var array
83
     */
84
    private $modules = [];
85
86
    /**
87
     * @var array
88
     */
89
    private $moduleMap = [];
90
91
    /**
92
     * @var array
93
     */
94
    private $themes = [];
95
96
    /**
97
     * @var array
98
     */
99
    private $themeMap = [];
100
101
    /**
102
     * @var ClassLoader
103
     */
104
    private $autoloader;
105
106
    /**
107
     * Flag determines if container is dumped or not
108
     *
109
     * @param $flag
110
     */
111
    public function setDump($flag)
112
    {
113
        $this->dump = $flag;
114
    }
115
116
    public function boot()
117
    {
118
        if (null === $this->autoloader) {
119
            $this->getAutoloader();
120
        }
121
122
        parent::boot();
123
124
        foreach ($this->bundles as $name => $bundle) {
125
            if ($bundle instanceof AbstractModule && !isset($this->modules[$name])) {
126
                $this->modules[$name] = $bundle;
127
            } elseif ($bundle instanceof AbstractTheme && !isset($this->themes[$name])) {
128
                $this->themes[$name] = $bundle;
129
            }
130
        }
131
132
        foreach ($this->bundleMap as $name => $bundles) {
133
            if ($bundles[0] instanceof AbstractModule) {
134
                $this->moduleMap[$name] = $bundles;
135
            } elseif ($bundles[0] instanceof AbstractTheme) {
136
                $this->themeMap[$name] = $bundles;
137
            }
138
        }
139
    }
140
141
    /**
142
     * Get named module bundle.
143
     *
144
     * @param string  $moduleName
145
     * @param boolean $first
146
     *
147
     * @throws \InvalidArgumentException when the bundle is not enabled
148
     * @return \Zikula\Core\AbstractModule|\Zikula\Core\AbstractModule[]
149
     */
150 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...
151
    {
152
        if (!isset($this->moduleMap[$moduleName])) {
153
            throw new \InvalidArgumentException(sprintf('Module "%s" does not exist or it is not enabled.', $moduleName, get_class($this)));
154
        }
155
156
        if (true === $first) {
157
            return $this->moduleMap[$moduleName][0];
158
        }
159
160
        return $this->moduleMap[$moduleName];
161
    }
162
163
    public function getModules()
164
    {
165
        return $this->modules;
166
    }
167
168
    /**
169
     * Checks if name is is the list of core modules.
170
     * @param $moduleName
171
     * @return bool
172
     */
173
    public static function isCoreModule($moduleName)
174
    {
175
        return array_key_exists($moduleName, self::$coreModules);
176
    }
177
178
    /**
179
     * Get named theme bundle.
180
     *
181
     * @param string  $themeName
182
     * @param boolean $first
183
     *
184
     * @throws \InvalidArgumentException when the bundle is not enabled
185
     *
186
     * @return AbstractTheme|AbstractTheme
187
     */
188 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...
189
    {
190
        if (!isset($this->themeMap[$themeName])) {
191
            throw new \InvalidArgumentException(sprintf('Theme "%s" does not exist or it is not enabled.', $themeName, get_class($this)));
192
        }
193
194
        if (true === $first) {
195
            return $this->themeMap[$themeName][0];
196
        }
197
198
        return $this->themeMap[$themeName];
199
    }
200
201
    public function getThemes()
202
    {
203
        return $this->themes;
204
    }
205
206
    public function getJustBundles()
207
    {
208
        $bundles = [];
209
        foreach ($this->bundles as $bundle) {
210
            if (!$bundle instanceof AbstractBundle) {
211
                $bundles[] = $bundle;
212
            }
213
        }
214
215
        return $bundles;
216
    }
217
218
    /**
219
     * Is this a Bundle?
220
     *
221
     * @param $name
222
     * @param bool $first
223
     * @return bool
224
     */
225
    public function isBundle($name, $first = true)
226
    {
227
        try {
228
            $this->getBundle($name, $first);
229
230
            return true;
231
        } catch (\Exception $e) {
232
            return false;
233
        }
234
    }
235
236
    public function setAutoloader(ClassLoader $autoloader)
237
    {
238
        $this->autoloader = $autoloader;
239
    }
240
241
    public function getAutoloader()
242
    {
243
        if (null === $this->autoloader) {
244
            $loaders = spl_autoload_functions();
245
            if ($loaders[0][0] instanceof DebugClassLoader) {
1 ignored issue
show
Bug introduced by
The class Symfony\Component\Debug\DebugClassLoader does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
246
                $classLoader = $loaders[0][0]->getClassLoader();
247
                if (is_callable($classLoader) && is_object($classLoader[0])) {
248
                    $this->autoloader = $classLoader[0];
249
                } elseif (is_object($classLoader)) {
250
                    $this->autoloader = $classLoader;
251
                }
252
            } else {
253
                $this->autoloader = $loaders[0][0];
254
            }
255
        }
256
257
        return $this->autoloader;
258
    }
259
260
    public function getConnectionConfig()
261
    {
262
        $config = Yaml::parse(file_get_contents($this->rootDir . '/config/parameters.yml'));
263 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...
264
            $config = array_merge($config, Yaml::parse(file_get_contents($file)));
265
        }
266
267
        return $config;
268
    }
269
270
    public function isClassInBundle($class)
271
    {
272
        /* @var BundleInterface $bundle */
273
        foreach ($this->getBundles() as $bundle) {
274
            if (0 === strpos($class, $bundle->getNamespace())) {
275
                return $bundle instanceof AbstractBundle;
276
            }
277
        }
278
279
        return false;
280
    }
281
282
    /**
283
     * Initializes the data structures related to the bundle management.
284
     *
285
     *  - the bundles property maps a bundle name to the bundle instance,
286
     *  - the bundleMap property maps a bundle name to the bundle inheritance hierarchy (most derived bundle first).
287
     *
288
     * @throws \LogicException if two bundles share a common name
289
     * @throws \LogicException if a bundle tries to extend a non-registered bundle
290
     * @throws \LogicException if a bundle tries to extend itself
291
     * @throws \LogicException if two bundles extend the same ancestor
292
     */
293
    protected function initializeBundles()
294
    {
295
        // init bundles
296
        $this->bundles = [];
297
        $topMostBundles = [];
298
        $directChildren = [];
299
300
        foreach ($this->registerBundles() as $bundle) {
301
            $name = $bundle->getName();
302
            if (isset($this->bundles[$name])) {
303
                throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s"', $name));
304
            }
305
            $this->bundles[$name] = $bundle;
306
307
            if ($parentName = $bundle->getParent()) {
308
                if (isset($directChildren[$parentName])) {
309
                    throw new \LogicException(sprintf('Bundle "%s" is directly extended by two bundles "%s" and "%s".', $parentName, $name, $directChildren[$parentName]));
310
                }
311
                if ($parentName == $name) {
312
                    throw new \LogicException(sprintf('Bundle "%s" can not extend itself.', $name));
313
                }
314
                $directChildren[$parentName] = $name;
315
            } else {
316
                $topMostBundles[$name] = $bundle;
317
            }
318
        }
319
320
        // look for orphans
321
        if (count($diff = array_values(array_diff(array_keys($directChildren), array_keys($this->bundles))))) {
322
            throw new \LogicException(sprintf('Bundle "%s" extends bundle "%s", which is not registered.', $directChildren[$diff[0]], $diff[0]));
323
        }
324
325
        // inheritance
326
        $this->bundleMap = [];
327
        foreach ($topMostBundles as $name => $bundle) {
328
            $bundleMap = [$bundle];
329
            $hierarchy = [$name];
330
331
            while (isset($directChildren[$name])) {
332
                $name = $directChildren[$name];
333
                array_unshift($bundleMap, $this->bundles[$name]);
334
                $hierarchy[] = $name;
335
            }
336
337
            foreach ($hierarchy as $bundle) {
338
                $this->bundleMap[$bundle] = $bundleMap;
339
                array_pop($bundleMap);
340
            }
341
        }
342
    }
343
344
    /**
345
     * Initializes the service container.
346
     *
347
     * The cached version of the service container is used when fresh, otherwise the
348
     * container is built.
349
     *
350
     * Overridden not to dump the container.
351
     */
352
    protected function initializeContainer()
353
    {
354
        if (true === $this->dump) {
355
            return parent::initializeContainer();
356
        }
357
358
        $this->container = $this->buildContainer();
359
        $this->container->set('kernel', $this);
360
    }
361
362
    /**
363
     * Dumps the service container to PHP code in the cache.
364
     *
365
     * @param ConfigCache      $cache     The config cache
366
     * @param SymfonyContainerBuilder $container The service container
367
     * @param string           $class     The name of the class to generate
368
     * @param string           $baseClass The name of the container's base class
369
     */
370
    protected function dumpContainer(ConfigCache $cache, SymfonyContainerBuilder $container, $class, $baseClass)
371
    {
372
        // cache the container
373
        $dumper = new PhpDumper($container);
374
        $content = $dumper->dump(['class' => $class, 'base_class' => $baseClass]);
375
        if (!$this->debug) {
376
            $content = self::stripComments($content);
377
        }
378
379
        $cache->write($content, $container->getResources());
380
    }
381
382
    /**
383
     * Gets the container's base class.
384
     *
385
     * All names except Container must be fully qualified.
386
     *
387
     * Allows container to build services after being dumped and frozen
388
     *
389
     * @return string
390
     */
391
    protected function getContainerBaseClass()
392
    {
393
        //return 'Symfony\Component\DependencyInjection\Container';
394
        return 'Zikula\Bridge\DependencyInjection\ContainerBuilder';
395
    }
396
397
    /**
398
     * Gets a new ContainerBuilder instance used to build the service container.
399
     *
400
     * @return ContainerBuilder
401
     */
402
    protected function getContainerBuilder()
403
    {
404
        return new ContainerBuilder(new ParameterBag($this->getKernelParameters()));
405
    }
406
407
    /**
408
     * Gets the environment parameters.
409
     *
410
     * Only the parameters starting with "ZIKULA__" are considered.
411
     *
412
     * @return array An array of parameters
413
     */
414
    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...
415
    {
416
        $parameters = parent::getEnvParameters();
417
        foreach ($_SERVER as $key => $value) {
418
            if (0 === strpos($key, 'ZIKULA__')) {
419
                $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
420
            }
421
        }
422
423
        return $parameters;
424
    }
425
426
    /**
427
     * Prepares the ContainerBuilder before it is compiled.
428
     *
429
     * @param SymfonyContainerBuilder $container A ContainerBuilder instance
430
     */
431
    protected function prepareContainer(SymfonyContainerBuilder $container)
432
    {
433
        $extensions = [];
434
        foreach ($this->bundles as $bundle) {
435
            if ($bundle instanceof AbstractBundle && $bundle->getState() != AbstractBundle::STATE_ACTIVE) {
436
                continue;
437
            }
438
            if ($extension = $bundle->getContainerExtension()) {
439
                $container->registerExtension($extension);
440
                $extensions[] = $extension->getAlias();
441
            }
442
443
            if ($this->debug) {
444
                $container->addObjectResource($bundle);
445
            }
446
        }
447
        foreach ($this->bundles as $bundle) {
448
            if ($bundle instanceof AbstractBundle && $bundle->getState() != AbstractBundle::STATE_ACTIVE) {
449
                continue;
450
            }
451
            $bundle->build($container);
452
        }
453
454
        // ensure these extensions are implicitly loaded
455
        $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions));
456
    }
457
458
    /**
459
     * {@inheritdoc}
460
     *
461
     * @throws \RuntimeException if a custom resource is hidden by a resource in a derived bundle
462
     */
463
    public function locateResource($name, $dir = null, $first = true)
464
    {
465
        $themeBundle = $this->container->get('zikula_core.common.theme_engine')->getTheme();
466
        $locations = parent::locateResource($name, $dir, false);
467
        if ($locations && (false !== strpos($locations[0], $dir))) {
468
            // if found in $dir (typically app/Resources) return it immediately.
469
            return $locations[0];
470
        }
471
472
        // add theme path to template locator
473
        // this method functions if the controller uses `@Template` or `ZikulaSpecModule:Foo:index.html.twig` naming scheme
474
        // if `@ZikulaSpecModule/Foo/index.html.twig` (name-spaced) naming scheme is used
475
        // the \Zikula\Bundle\CoreBundle\EventListener\Theme\TemplatePathOverrideListener::setUpThemePathOverrides method is used instead
476
        if ($themeBundle && (false === strpos($name, $themeBundle->getName()))) {
477
            // do not add theme override path to theme files
478
            $customThemePath = $themeBundle->getPath() . '/Resources';
479
480
            return parent::locateResource($name, $customThemePath, true);
481
        }
482
483
        return $locations[0];
484
    }
485
}
486