Completed
Pull Request — master (#2144)
by Gilles
10:55
created

Thelia::checkMySQLConfigurations()   C

Complexity

Conditions 11
Paths 61

Size

Total Lines 48
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 48
rs 5.2653
cc 11
eloc 26
nc 61
nop 1

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
/*      This file is part of the Thelia package.                                     */
4
/*                                                                                   */
5
/*      Copyright (c) OpenStudio                                                     */
6
/*      email : [email protected]                                                       */
7
/*      web : http://www.thelia.net                                                  */
8
/*                                                                                   */
9
/*      For the full copyright and license information, please view the LICENSE.txt  */
10
/*      file that was distributed with this source code.                             */
11
/*************************************************************************************/
12
13
namespace Thelia\Core;
14
15
/**
16
 * Root class of Thelia
17
 *
18
 * It extends Symfony\Component\HttpKernel\Kernel for changing some features
19
 *
20
 *
21
 * @author Manuel Raynaud <[email protected]>
22
 */
23
24
use Propel\Runtime\Connection\ConnectionManagerSingle;
25
use Propel\Runtime\Connection\ConnectionWrapper;
26
use Propel\Runtime\Propel;
27
use Symfony\Component\Config\ConfigCache;
28
use Symfony\Component\Config\FileLocator;
29
use Symfony\Component\Config\Loader\LoaderInterface;
30
use Symfony\Component\Config\Resource\FileResource;
31
use Symfony\Component\Debug\Debug;
32
use Symfony\Component\DependencyInjection\ContainerBuilder;
33
use Symfony\Component\DependencyInjection\Definition;
34
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
35
use Symfony\Component\DependencyInjection\Reference;
36
use Symfony\Component\Finder\Finder;
37
use Symfony\Component\HttpKernel\Kernel;
38
use Symfony\Component\Yaml\Yaml;
39
use Thelia\Config\DatabaseConfiguration;
40
use Thelia\Config\DefinePropel;
41
use Thelia\Core\DependencyInjection\Loader\XmlFileLoader;
42
use Thelia\Core\Event\TheliaEvents;
43
use Thelia\Core\Template\ParserInterface;
44
use Thelia\Core\Template\TemplateDefinition;
45
use Thelia\Core\Translation\Translator;
46
use Thelia\Log\Tlog;
47
use Thelia\Model\Map\ProductTableMap;
48
use Thelia\Model\Module;
49
use Thelia\Model\ModuleQuery;
50
51
class Thelia extends Kernel
52
{
53
    const THELIA_VERSION = '2.3.0';
54
55
    public function __construct($environment, $debug)
56
    {
57
        parent::__construct($environment, $debug);
58
59
        if ($debug) {
60
            Debug::enable();
61
        }
62
63
        $this->initPropel();
64
    }
65
66
    public static function isInstalled()
67
    {
68
        return file_exists(THELIA_CONF_DIR . 'database.yml');
69
    }
70
71
    protected function initPropel()
72
    {
73
        if (self::isInstalled() === false) {
74
            return ;
75
        }
76
77
        /** @var \Propel\Runtime\ServiceContainer\StandardServiceContainer $serviceContainer */
78
        $serviceContainer = Propel::getServiceContainer();
79
        $serviceContainer->setDefaultDatasource('thelia');
80
81
        $manager = new ConnectionManagerSingle();
82
        $manager->setConfiguration($this->getPropelConfig());
83
        $manager->setName('thelia');
84
85
        $serviceContainer->setConnectionManager('thelia', $manager);
86
        $serviceContainer->setAdapterClass('thelia', 'mysql');
87
88
        /** @var ConnectionWrapper $con */
89
        $con = Propel::getConnection(ProductTableMap::DATABASE_NAME);
90
        $con->setAttribute(ConnectionWrapper::PROPEL_ATTR_CACHE_PREPARES, true);
91
92
        if ($this->isDebug()) {
93
            // In debug mode, we have to initialize Tlog at this point, as this class uses Propel
94
            Tlog::getInstance()->setLevel(Tlog::DEBUG);
95
96
            $serviceContainer->setLogger('defaultLogger', Tlog::getInstance());
97
            $con->useDebug(true);
98
        }
99
100
        $this->checkMySQLConfigurations($con);
101
    }
102
103
    protected function checkMySQLConfigurations(ConnectionWrapper $con)
104
    {
105
        // todo add cache for this test
106
        $result = $con->query("SELECT VERSION() as version, @@SESSION.sql_mode as session_sql_mode");
107
108
        if ($result && $data = $result->fetch(\PDO::FETCH_ASSOC)) {
109
            $sessionSqlMode = explode(',', $data['session_sql_mode']);
110
            if (empty($sessionSqlMode[0])) {
111
                unset($sessionSqlMode[0]);
112
            }
113
            $canUpdate = false;
114
115
            // MariaDB is not impacted by this problem
116
            if (false === strpos($data['version'], 'MariaDB')) {
117
                // MySQL 5.6+ compatibility
118
                if (version_compare($data['version'], '5.6.0', '>=')) {
119
                    // add NO_ENGINE_SUBSTITUTION
120
                    if (!in_array('NO_ENGINE_SUBSTITUTION', $sessionSqlMode)) {
121
                        $sessionSqlMode[] = 'NO_ENGINE_SUBSTITUTION';
122
                        $canUpdate = true;
123
                        Tlog::getInstance()->addWarning("Add sql_mode NO_ENGINE_SUBSTITUTION. Please configure your MySQL server.");
124
                    }
125
126
                    // remove STRICT_TRANS_TABLES
127
                    if (($key = array_search('STRICT_TRANS_TABLES', $sessionSqlMode)) !== false) {
128
                        unset($sessionSqlMode[$key]);
129
                        $canUpdate = true;
130
                        Tlog::getInstance()->addWarning("Remove sql_mode STRICT_TRANS_TABLES. Please configure your MySQL server.");
131
                    }
132
133
                    // remove ONLY_FULL_GROUP_BY
134
                    if (($key = array_search('ONLY_FULL_GROUP_BY', $sessionSqlMode)) !== false) {
135
                        unset($sessionSqlMode[$key]);
136
                        $canUpdate = true;
137
                        Tlog::getInstance()->addWarning("Remove sql_mode ONLY_FULL_GROUP_BY. Please configure your MySQL server.");
138
                    }
139
                }
140
            }
141
142
            if (! empty($canUpdate)) {
143
                if (null === $con->query("SET SESSION sql_mode='" . implode(',', $sessionSqlMode) . "';")) {
144
                    throw new \RuntimeException('Failed to set MySQL global and session sql_mode');
145
                }
146
            }
147
        } else {
148
            Tlog::getInstance()->addWarning("Failed to get MySQL version and sql_mode");
149
        }
150
    }
151
152
    /**
153
     * Gets the container's base class.
154
     *
155
     * All names except Container must be fully qualified.
156
     *
157
     * @return string
158
     */
159
    protected function getContainerBaseClass()
160
    {
161
        return '\Thelia\Core\DependencyInjection\TheliaContainer';
162
    }
163
164
    /**
165
     *
166
     * process the configuration and create a cache.
167
     *
168
     * @return array configuration for propel
169
     */
170
    protected function getPropelConfig()
171
    {
172
        $cachePath = $this->getCacheDir() . DS . 'PropelConfig.php';
173
174
        $cache = new ConfigCache($cachePath, $this->debug);
175
176
        if (!$cache->isFresh()) {
177
            if (file_exists(THELIA_CONF_DIR."database_".$this->environment.".yml")) {
178
                $file = THELIA_CONF_DIR."database_".$this->environment.".yml";
179
            } else {
180
                $file = THELIA_CONF_DIR . 'database.yml';
181
            }
182
183
            $definePropel = new DefinePropel(
184
                new DatabaseConfiguration(),
185
                Yaml::parse(file_get_contents($file)),
186
                $this->getEnvParameters()
187
            );
188
189
            $resource = [
190
                new FileResource($file)
191
            ];
192
193
            $config = $definePropel->getConfig();
194
195
            $code = sprintf("<?php return %s;", var_export($config, true));
196
197
            $cache->write($code, $resource);
198
        }
199
200
        $config = require $cachePath;
201
202
        return $config;
203
    }
204
205
    /**
206
     * dispatch an event when application is boot
207
     */
208
    public function boot()
209
    {
210
        parent::boot();
211
212
        if (self::isInstalled()) {
213
            $this->getContainer()->get("event_dispatcher")->dispatch(TheliaEvents::BOOT);
214
        }
215
    }
216
217
    /**
218
     * Add all module's standard templates to the parser environment
219
     *
220
     * @param ParserInterface $parser the parser
221
     * @param Module          $module the Module.
222
     */
223
    protected function addStandardModuleTemplatesToParserEnvironment($parser, $module)
224
    {
225
        $stdTpls = TemplateDefinition::getStandardTemplatesSubdirsIterator();
226
227
        foreach ($stdTpls as $templateType => $templateSubdirName) {
228
            $this->addModuleTemplateToParserEnvironment($parser, $module, $templateType, $templateSubdirName);
229
        }
230
    }
231
232
    /**
233
     * Add a module template directory to the parser environment
234
     *
235
     * @param ParserInterface $parser             the parser
236
     * @param Module          $module             the Module.
237
     * @param string          $templateType       the template type (one of the TemplateDefinition type constants)
238
     * @param string          $templateSubdirName the template subdirectory name (one of the TemplateDefinition::XXX_SUBDIR constants)
239
     */
240
    protected function addModuleTemplateToParserEnvironment($parser, $module, $templateType, $templateSubdirName)
241
    {
242
        // Get template path
243
        $templateDirectory = $module->getAbsoluteTemplateDirectoryPath($templateSubdirName);
244
        try {
245
            $templateDirBrowser = new \DirectoryIterator($templateDirectory);
246
247
            $code = ucfirst($module->getCode());
248
249
            /* browse the directory */
250
            foreach ($templateDirBrowser as $templateDirContent) {
251
                /* is it a directory which is not . or .. ? */
252
                if ($templateDirContent->isDir() && ! $templateDirContent->isDot()) {
253
                    $parser->addMethodCall(
0 ignored issues
show
Bug introduced by
The method addMethodCall() does not seem to exist on object<Thelia\Core\Template\ParserInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
254
                        'addTemplateDirectory',
255
                        array(
256
                            $templateType,
257
                            $templateDirContent->getFilename(),
258
                            $templateDirContent->getPathName(),
259
                            $code
260
                        )
261
                    );
262
                }
263
            }
264
        } catch (\UnexpectedValueException $ex) {
265
            // The directory does not exists, ignore it.
266
        }
267
    }
268
269
    /**
270
     *
271
     * Load some configuration
272
     * Initialize all plugins
273
     *
274
     */
275
    protected function loadConfiguration(ContainerBuilder $container)
276
    {
277
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . "/../Config/Resources"));
278
        $finder = Finder::create()
279
            ->name('*.xml')
280
            ->depth(0)
281
            ->in(__DIR__ . "/../Config/Resources");
282
283
        /** @var \SplFileInfo $file */
284
        foreach ($finder as $file) {
285
            $loader->load($file->getBaseName());
286
        }
287
288
        if (defined("THELIA_INSTALL_MODE") === false) {
289
            $modules = ModuleQuery::getActivated();
290
291
            $translationDirs = array();
292
293
294
295
            /** @var Module $module */
296
            foreach ($modules as $module) {
297
                try {
298
                    $definition = new Definition();
299
                    $definition->setClass($module->getFullNamespace());
300
                    $definition->addMethodCall("setContainer", array(new Reference('service_container')));
301
302
                    $container->setDefinition(
303
                        "module." . $module->getCode(),
304
                        $definition
305
                    );
306
307
                    $compilers = call_user_func(array($module->getFullNamespace(), 'getCompilers'));
308
309
                    foreach ($compilers as $compiler) {
310
                        if (is_array($compiler)) {
311
                            $container->addCompilerPass($compiler[0], $compiler[1]);
312
                        } else {
313
                            $container->addCompilerPass($compiler);
314
                        }
315
                    }
316
317
                    $loader = new XmlFileLoader($container, new FileLocator($module->getAbsoluteConfigPath()));
318
                    $loader->load("config.xml", "module." . $module->getCode());
319
320
                    $envConfigFileName = sprintf("config_%s.xml", $this->environment);
321
                    $envConfigFile = sprintf('%s%s%s', $module->getAbsoluteConfigPath(), DS, $envConfigFileName);
322
323
                    if (is_file($envConfigFile) && is_readable($envConfigFile)) {
324
                        $loader->load($envConfigFileName, "module." . $module->getCode());
325
                    }
326
                } catch (\Exception $e) {
327
                    Tlog::getInstance()->addError(
328
                        sprintf("Failed to load module %s: %s", $module->getCode(), $e->getMessage()),
329
                        $e
330
                    );
331
                }
332
            }
333
334
            /** @var ParserInterface $parser */
335
            $parser = $container->getDefinition('thelia.parser');
336
337
            /** @var \Thelia\Core\Template\TemplateHelperInterface $templateHelper */
338
            $templateHelper = $container->get('thelia.template_helper');
339
340
            /** @var Module $module */
341
            foreach ($modules as $module) {
342
                try {
343
                    $this->loadModuleTranslationDirectories($module, $translationDirs, $templateHelper);
344
345
                    $this->addStandardModuleTemplatesToParserEnvironment($parser, $module);
346
                } catch (\Exception $e) {
347
                    Tlog::getInstance()->addError(
348
                        sprintf("Failed to load module %s: %s", $module->getCode(), $e->getMessage()),
349
                        $e
350
                    );
351
                }
352
            }
353
354
            // Load core translation
355
            $translationDirs['core'] = THELIA_LIB . 'Config' . DS . 'I18n';
356
357
            // Load core translation
358
            $translationDirs[Translator::GLOBAL_FALLBACK_DOMAIN] = THELIA_LOCAL_DIR . 'I18n';
359
360
            // Standard templates (front, back, pdf, mail)
361
362
            /** @var TemplateDefinition $templateDefinition */
363
            foreach ($templateHelper->getStandardTemplateDefinitions() as $templateDefinition) {
364
                if (is_dir($dir = $templateDefinition->getAbsoluteI18nPath())) {
365
                    $translationDirs[$templateDefinition->getTranslationDomain()] = $dir;
366
                }
367
            }
368
369
            if ($translationDirs) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $translationDirs of type array<*,string> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
370
                $this->loadTranslation($container, $translationDirs);
371
            }
372
        }
373
    }
374
375
    private function loadModuleTranslationDirectories(Module $module, array &$translationDirs, $templateHelper)
376
    {
377
        // Core module translation
378
        if (is_dir($dir = $module->getAbsoluteI18nPath())) {
379
            $translationDirs[$module->getTranslationDomain()] = $dir;
380
        }
381
382
        // Admin includes translation
383
        if (is_dir($dir = $module->getAbsoluteAdminIncludesI18nPath())) {
384
            $translationDirs[$module->getAdminIncludesTranslationDomain()] = $dir;
385
        }
386
387
        // Module back-office template, if any
388
        $templates =
389
            $templateHelper->getList(
390
                TemplateDefinition::BACK_OFFICE,
391
                $module->getAbsoluteTemplateBasePath()
392
            );
393
394
        foreach ($templates as $template) {
395
            $translationDirs[$module->getBackOfficeTemplateTranslationDomain($template->getName())] =
396
                $module->getAbsoluteBackOfficeI18nTemplatePath($template->getName());
397
        }
398
399
        // Module front-office template, if any
400
        $templates =
401
            $templateHelper->getList(
402
                TemplateDefinition::FRONT_OFFICE,
403
                $module->getAbsoluteTemplateBasePath()
404
            );
405
406
        foreach ($templates as $template) {
407
            $translationDirs[$module->getFrontOfficeTemplateTranslationDomain($template->getName())] =
408
                $module->getAbsoluteFrontOfficeI18nTemplatePath($template->getName());
409
        }
410
411
        // Module pdf template, if any
412
        $templates =
413
            $templateHelper->getList(
414
                TemplateDefinition::PDF,
415
                $module->getAbsoluteTemplateBasePath()
416
            );
417
418
        foreach ($templates as $template) {
419
            $translationDirs[$module->getPdfTemplateTranslationDomain($template->getName())] =
420
                $module->getAbsolutePdfI18nTemplatePath($template->getName());
421
        }
422
423
        // Module email template, if any
424
        $templates =
425
            $templateHelper->getList(
426
                TemplateDefinition::EMAIL,
427
                $module->getAbsoluteTemplateBasePath()
428
            );
429
430
        foreach ($templates as $template) {
431
            $translationDirs[$module->getEmailTemplateTranslationDomain($template->getName())] =
432
                $module->getAbsoluteEmailI18nTemplatePath($template->getName());
433
        }
434
    }
435
436
    private function loadTranslation(ContainerBuilder $container, array $dirs)
437
    {
438
        $translator = $container->getDefinition('thelia.translator');
439
440
        foreach ($dirs as $domain => $dir) {
441
            try {
442
                $finder = Finder::create()
443
                    ->files()
444
                    ->depth(0)
445
                    ->in($dir);
446
447
                /** @var \DirectoryIterator $file */
448
                foreach ($finder as $file) {
449
                    list($locale, $format) = explode('.', $file->getBaseName(), 2);
450
451
                    $translator->addMethodCall('addResource', array($format, (string) $file, $locale, $domain));
452
                }
453
            } catch (\InvalidArgumentException $ex) {
454
                // Ignore missing I18n directories
455
                Tlog::getInstance()->addWarning("loadTranslation: missing $dir directory");
456
            }
457
        }
458
    }
459
460
    /**
461
     *
462
     * initialize session in Request object
463
     *
464
     * All param must be change in Config table
465
     *
466
     * @param \Symfony\Component\HttpFoundation\Request $request
467
     */
468
469
    /**
470
     * Gets a new ContainerBuilder instance used to build the service container.
471
     *
472
     * @return ContainerBuilder
473
     */
474
    protected function getContainerBuilder()
475
    {
476
        return new TheliaContainerBuilder(new ParameterBag($this->getKernelParameters()));
477
    }
478
479
    /**
480
     * Builds the service container.
481
     *
482
     * @return ContainerBuilder The compiled service container
483
     *
484
     * @throws \RuntimeException
485
     */
486
    protected function buildContainer()
487
    {
488
        $container = parent::buildContainer();
489
490
        $this->loadConfiguration($container);
491
        $container->customCompile();
0 ignored issues
show
Bug introduced by
The method customCompile() does not exist on Symfony\Component\Depend...ection\ContainerBuilder. Did you maybe mean compile()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
492
493
        return $container;
494
    }
495
496
    /**
497
     * Gets the cache directory.
498
     *
499
     * @return string The cache directory
500
     *
501
     * @api
502
     */
503
    public function getCacheDir()
504
    {
505
        if (defined('THELIA_ROOT')) {
506
            return THELIA_CACHE_DIR . $this->environment;
507
        } else {
508
            return parent::getCacheDir();
509
        }
510
    }
511
512
    /**
513
     * Gets the log directory.
514
     *
515
     * @return string The log directory
516
     *
517
     * @api
518
     */
519
    public function getLogDir()
520
    {
521
        if (defined('THELIA_ROOT')) {
522
            return THELIA_LOG_DIR;
523
        } else {
524
            return parent::getLogDir();
525
        }
526
    }
527
528
    /**
529
     * Returns the kernel parameters.
530
     *
531
     * @return array An array of kernel parameters
532
     */
533
    protected function getKernelParameters()
534
    {
535
        $parameters = parent::getKernelParameters();
536
537
        $parameters["thelia.root_dir"] = THELIA_ROOT;
538
        $parameters["thelia.core_dir"] = dirname(__DIR__); // This class is in core/lib/Thelia/Core.
539
        $parameters["thelia.module_dir"] = THELIA_MODULE_DIR;
540
541
        return $parameters;
542
    }
543
544
    /**
545
     * return available bundle
546
     *
547
     * Part of Symfony\Component\HttpKernel\KernelInterface
548
     *
549
     * @return array An array of bundle instances.
550
     *
551
     */
552
    public function registerBundles()
553
    {
554
        $bundles = array(
555
            /* TheliaBundle contain all the dependency injection description */
556
            new Bundle\TheliaBundle(),
557
        );
558
559
        /**
560
         * OTHER CORE BUNDLE CAN BE DECLARE HERE AND INITIALIZE WITH SPECIFIC CONFIGURATION
561
         *
562
         * HOW TO DECLARE OTHER BUNDLE ? ETC
563
         */
564
565
        return $bundles;
566
    }
567
568
    /**
569
     * Loads the container configuration
570
     *
571
     * part of Symfony\Component\HttpKernel\KernelInterface
572
     *
573
     * @param LoaderInterface $loader A LoaderInterface instance
574
     *
575
     * @api
576
     */
577
    public function registerContainerConfiguration(LoaderInterface $loader)
578
    {
579
        //Nothing is load here but it's possible to load container configuration here.
580
        //exemple in sf2 : $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
581
    }
582
}
583