Failed Conditions
Pull Request — experimental/3.1 (#2550)
by chihiro
34:58
created

Application   F

Complexity

Total Complexity 118

Size/Duplication

Total Lines 1097
Duplicated Lines 2.64 %

Coupling/Cohesion

Components 2
Dependencies 91

Test Coverage

Coverage 76.35%

Importance

Changes 0
Metric Value
wmc 118
lcom 2
cbo 91
dl 29
loc 1097
ccs 397
cts 520
cp 0.7635
rs 0.5373
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 8 2
A clearInstance() 0 4 1
A __clone() 0 4 1
A __construct() 0 17 2
A isBooted() 0 4 1
B initConfig() 0 25 2
A initLogger() 0 5 1
B initClassLoader() 0 26 3
D initialize() 26 232 17
B initLocale() 0 29 5
B initSession() 0 24 3
D initRendering() 0 139 20
C initMailer() 0 29 8
F initDoctrine() 0 194 18
B initSecurity() 0 99 3
B initProxy() 3 12 5
A initializePlugin() 0 15 4
A setTestMode() 0 4 1
A isTestMode() 0 4 1
B checkDatabaseConnection() 0 24 3
B parseConfig() 0 33 5
B isSessionStarted() 0 12 5
B initCacheRequest() 0 63 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Application often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Application, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
namespace Eccube;
25
26
use Composer\Autoload\ClassLoader;
27
use Doctrine\DBAL\Types\Type;
28
use Eccube\DI\AutoWiring\EntityEventAutowiring;
29
use Eccube\DI\AutoWiring\FormExtensionAutoWiring;
30
use Eccube\DI\AutoWiring\FormTypeAutoWiring;
31
use Eccube\DI\AutoWiring\QueryExtensionAutoWiring;
32
use Eccube\DI\AutoWiring\RepositoryAutoWiring;
33
use Eccube\DI\AutoWiring\RouteAutoWiring;
34
use Eccube\DI\AutoWiring\ServiceAutoWiring;
35
use Eccube\Doctrine\DBAL\Types\UTCDateTimeType;
36
use Eccube\Doctrine\DBAL\Types\UTCDateTimeTzType;
37
use Eccube\Doctrine\EventSubscriber\InitSubscriber;
38
use Eccube\Doctrine\ORM\Mapping\Driver\AnnotationDriver;
39
use Eccube\Entity\BaseInfo;
40
use Eccube\Plugin\ConfigManager as PluginConfigManager;
41
use Eccube\Routing\EccubeRouter;
42
use Eccube\ServiceProvider\CompatRepositoryProvider;
43
use Eccube\ServiceProvider\CompatServiceProvider;
44
use Eccube\DI\DIServiceProvider;
45
use Eccube\ServiceProvider\EntityEventServiceProvider;
46
use Eccube\ServiceProvider\MobileDetectServiceProvider;
47
use Eccube\ServiceProvider\TwigLintServiceProvider;
48
use Sergiors\Silex\Routing\ChainUrlGenerator;
49
use Sergiors\Silex\Routing\ChainUrlMatcher;
50
use Symfony\Component\Dotenv\Dotenv;
51
use Symfony\Component\HttpFoundation\Request;
52
use Symfony\Component\HttpFoundation\Response;
53
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
54
use Symfony\Component\HttpKernel\KernelEvents;
55
56
class Application extends \Silex\Application
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
57
{
58
    use \Silex\Application\FormTrait;
59
    use \Silex\Application\UrlGeneratorTrait;
60
    use \Silex\Application\MonologTrait;
61
    use \Silex\Application\SwiftmailerTrait;
62
    use \Silex\Application\SecurityTrait;
63
    use \Silex\Application\TranslationTrait;
64
    use \Eccube\Application\ApplicationTrait;
65
    use \Eccube\Application\SecurityTrait;
66
    use \Eccube\Application\TwigTrait;
67
68
    protected static $instance;
69
70
    protected $initialized = false;
71
    protected $initializedPlugin = false;
72
    protected $testMode = false;
73 1069
74
    public static function getInstance(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
75 1069
    {
76 1069
        if (!is_object(self::$instance)) {
77
            self::$instance = new Application($values);
78
        }
79 1069
80
        return self::$instance;
81
    }
82 1069
83
    public static function clearInstance()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
84 1069
    {
85
        self::$instance = null;
86
    }
87
88
    final public function __clone()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
89
    {
90
        throw new \Exception('Clone is not allowed against '.get_class($this));
91
    }
92 1070
93
    public function __construct(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
94 1070
    {
95
        parent::__construct($values);
96 1070
97 1070
        if (is_null(self::$instance)) {
98
            self::$instance = $this;
99
        }
100
101 1070
        // load config
102
        $this->initConfig();
103
104 1070
        // init monolog
105
        $this->initLogger();
106
107
        // init class loader.
108
        $this->initClassLoader();
109
    }
110
111
    /**
112 1069
     * Application::runが実行されているか親クラスのプロパティから判定
113
     *
114 1069
     * @return bool
115
     */
116
    public function isBooted()
117 1070
    {
118
        return $this->booted;
119
    }
120 1070
121 1070
    public function initConfig()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
122 1070
    {
123
        // load .env
124
        $envFile = __DIR__.'/../../.env';
125
        if (file_exists($envFile)) {
126
            (new Dotenv())->load($envFile);
127 1070
        }
128 1070
129 1070
        // load config
130 1070
        $this['config'] = function() {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
131 1070
            $configAll = array();
132 1070
            $this->parseConfig('constant', $configAll)
133 1070
                ->parseConfig('path', $configAll)
134 1070
                ->parseConfig('config', $configAll)
135 1070
                ->parseConfig('database', $configAll)
136 1070
                ->parseConfig('mail', $configAll)
137 1070
                ->parseConfig('log', $configAll)
138
                ->parseConfig('nav', $configAll, true)
139 1070
                ->parseConfig('doctrine_cache', $configAll)
140
                ->parseConfig('http_cache', $configAll)
141
                ->parseConfig('session_handler', $configAll);
142
143 1070
            return $configAll;
144
        };
145 1070
    }
146 1070
147
    public function initLogger()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
148
    {
149 1069
        $app = $this;
150
        $this->register(new ServiceProvider\LogServiceProvider($app));
0 ignored issues
show
Unused Code introduced by
The call to LogServiceProvider::__construct() has too many arguments starting with $app.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
151 1069
    }
152 2
153
    public function initClassLoader()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
154
    {
155
        if (!isset($this['config']['vendor_name'])) {
156 1069
            $this['logger']->log('config.vendor_name is not set.');
157
158
            return;
159 1069
        }
160 1069
161
        $name = $this['config']['vendor_name'];
162
        $dir = $this['config']['root_dir'].'/app/'.$name;
163
164 1069
        if (false === file_exists($dir)) {
165
            $this['logger']->log(sprintf('%s is not exists.', $dir));
166
167 1069
            return;
168 1069
        }
169
170 1069
        $path = realpath($dir);
171 1069
172 1069
        $loader = $this['eccube.autoloader'];
173 1069
        $loader->addPsr4($name.'\\', $path);
174 1069
175 1069
        $config = $this['config'];
176 1069
        $config['vendor_dir'] = $path;
177
        $this->overwrite('config', $config);
178
    }
179 25
180 25
    public function initialize()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
181
    {
182
        if ($this->initialized) {
183
            return;
184
        }
185
186
        // init locale
187
        $this->initLocale();
188
189
        // init session
190
        if (!$this->isSessionStarted()) {
191
            $this->initSession();
192
        }
193
194
        // init twig
195
        $this->initRendering();
196
197
        // init provider
198
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
199
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
200
        ));
201
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
202 1069
        $this->register(new \Silex\Provider\FormServiceProvider());
203
        $this->register(new \Silex\Provider\SerializerServiceProvider());
204
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
205 1069
        $this->register(new \Saxulum\Validator\Provider\SaxulumValidatorProvider());
206
        $this->register(new MobileDetectServiceProvider());
207 1069
        $this->register(new TwigLintServiceProvider());
208 1069
209 1069
        $this->error(function (\Exception $e, Request $request, $code) {
210
            if ($this['debug']) {
211 1069
                return;
212 1069
            }
213
214
            switch ($code) {
215
                case 403:
216
                    $title = 'アクセスできません。';
217 1069
                    $message = 'お探しのページはアクセスができない状況にあるか、移動もしくは削除された可能性があります。';
218
                    break;
219
                case 404:
220 1069
                    $title = 'ページがみつかりません。';
221
                    $message = 'URLに間違いがないかご確認ください。';
222
                    break;
223 1069
                default:
224
                    $title = 'システムエラーが発生しました。';
225 1069
                    $message = '大変お手数ですが、サイト管理者までご連絡ください。';
226 1069
                    break;
227
            }
228 1069
229 1069
            return $this->render('error.twig', array(
230 1069
                'error_title' => $title,
231
                'error_message' => $message,
232
            ));
233
        });
234
235 1069
        // init mailer
236
        $this->initMailer();
237 1069
238 1069
        $this->register(new \Sergiors\Silex\Provider\DoctrineCacheServiceProvider());
239
        $this->register(new \Sergiors\Silex\Provider\AnnotationsServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
240
            'annotations.debug' => $this['debug'],
241 1069
            'annotations.options' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
242
                'cache_driver' => $this['debug'] ? 'array' : 'filesystem',
243
                'cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/annotation'
244
            ]
245
        ]);
246 1069
247 1069
        // init doctrine orm
248
        $this->initDoctrine();
249
250 1069
        // Set up the DBAL connection now to check for a proper connection to the database.
251
        $this->checkDatabaseConnection();
252 1069
253 1069
        // init security
254 1069
        $this->initSecurity();
255 1069
256 1069
        $this->register(new \Sergiors\Silex\Provider\RoutingServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
257 1069
            'routing.cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/routing'
258 1069
        ]);
259 1069
        $this->register(new \Sergiors\Silex\Provider\TemplatingServiceProvider());
260 1069
        $this->register(new \Sergiors\Silex\Provider\SensioFrameworkExtraServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
261 1069
            'request' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
262 1069
                'auto_convert' => true
263 1069
            ]
264 1069
        ]);
265 1069
        // init proxy
266 1069
        $this->initProxy();
267 1069
268 1069
        $enabledPlugins = $this['orm.em']->getRepository('Eccube\Entity\Plugin')->findAllEnabled();
269 1069
        $configRootDir = $this['config']['root_dir'];
270 1069
        $enabledPluginDirs = array_map(function($plugin) use ($configRootDir) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
271 1069
            return $configRootDir.'/app/Plugin/'.$plugin->getCode();
272 1069
        }, $enabledPlugins);
273 1069
274
        $pluginSubDirs = (function($dirName) use ($enabledPluginDirs) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
275 1069
            return array_map(function($pluginDir) use ($dirName) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
276
                return $pluginDir . '/' . $dirName;
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
277
            }, $enabledPluginDirs);
278 1069
        });
279 1069
280 1069
        // init ec-cube service provider
281
        $this->register(new DIServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
282 1069
            'eccube.di.wirings' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
283 1069
                new RouteAutoWiring(array_merge([
284
                    $this['config']['vendor_dir'].'/Controller',
285
                    $this['config']['root_dir'].'/src/Eccube/Controller',
286
                ], $pluginSubDirs('Controller'))),
287 1069
                new FormTypeAutoWiring(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
288
                    $this['config']['vendor_dir'].'/Form/Type',
289
                    $this['config']['root_dir'].'/src/Eccube/Form/Type'
290 1069
                ], $pluginSubDirs('Form/Type'))),
291 1069
                new FormExtensionAutoWiring(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
292 1069
                    $this['config']['vendor_dir'].'/Form/Extension',
293 1069
                    $this['config']['root_dir'].'/src/Eccube/Form/Extension'
294 1069
                ], $pluginSubDirs('Form/Extension'))),
295 1069
                new ServiceAutoWiring(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
296
                    $this['config']['vendor_dir'].'/Service',
297 1069
                    $this['config']['root_dir'].'/src/Eccube/Service'
298 1069
                ], $pluginSubDirs('Service'))),
299 1069
                new RepositoryAutoWiring(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
300 1069
                    $this['config']['vendor_dir'].'/Repository',
301 1069
                    $this['config']['root_dir'].'/src/Eccube/Repository'
302 1069
                ], $pluginSubDirs('Repository'))),
303
                new QueryExtensionAutoWiring(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
304
                    $this['config']['vendor_dir'].'/Repository'
305 1069
                ], $pluginSubDirs('Repository'))),
306 1069
                new EntityEventAutowiring(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
307 1069
                    $this['config']['vendor_dir'].'/Entity'
308
                ], $pluginSubDirs('Entity')))
309 1069
            ],
310 1069
            'eccube.di.generator.dir' => $this['config']['root_dir'].'/app/cache/provider'
311
        ]);
312
313 1069
        $this->register(new CompatRepositoryProvider());
314 1069
        $this->register(new CompatServiceProvider());
315
        $this->register(new ServiceProvider\EccubeServiceProvider());
316 1069
317
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
318
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
319 1069
320
        // ルーティングの設定
321
        // TODO EccubeRoutingServiceProviderに移植する.
322
        $app = $this;
323 1069
        $this['eccube.router'] = $this->protect(function($resoure, $cachePrefix) use ($app) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
324 1069
            $options = [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
325
                'debug' => $app['debug'],
326 1069
                'cache_dir' => $app['routing.cache_dir'],
327
                'matcher_base_class' => $app['request_matcher_class'],
328 1069
                'matcher_class' => $app['request_matcher_class'],
329
                'matcher_cache_class' => $cachePrefix.'UrlMatcher',
330
                'generator_cache_class' => $cachePrefix.'UrlGenerator'
331
            ];
332 1069
            $router = new EccubeRouter(
333 1069
                $app['routing.loader'],
334 1069
                $resoure,
335
                $options,
336
                $app['request_context'],
337 1069
                $app['logger']
338 1069
            );
339
340 1069
            $router->setAdminPrefix($app['config']['admin_route']);
341 1069
            $router->setUserDataPrefix($app['config']['user_data_route']);
342
            $router->setRequireHttps($app['config']['force_ssl']);
343
344 1069
            return $router;
345 1069
        });
346 1069
347
        $this['eccube.router.origin'] = function ($app) {
348
            $resource = __DIR__.'/Controller';
349 1069
            $cachePrefix = 'Origin';
350 1069
351
            return $app['eccube.router']($resource, $cachePrefix);
352 1069
        };
353 1069
354
        $this['eccube.routers.plugin'] = [];
355
356
        if (isset($this['config']['vendor_dir']) && file_exists($this['config']['vendor_dir'].'/Controller')) {
357 1069
            $this['eccube.router.extend'] = function ($app) {
358 1069
                $resource = $app['config']['vendor_dir'].'/Controller';
359
                $cachePrefix = 'Extend';
360
361 1069
                $router = $app['eccube.router']($resource, $cachePrefix);
362
363 1069
                return $router;
364 1069
            };
365
        }
366 View Code Duplication
        $this->extend('request_matcher', function ($matcher, $app) {
367 1069
            $matchers = [];
368
            if (isset($app['eccube.router.extend'])) {
369 1069
                $matchers[] = $app['eccube.router.extend'];
370
            }
371
            foreach ($app['eccube.routers.plugin'] as $router) {
372 1069
                $matchers[] = $router;
373
            };
374
            $matchers[] = $app['eccube.router.origin'];
375 1069
            $matchers[] = $matcher;
376 1069
377
            return new ChainUrlMatcher($matchers, $app['request_context']);
378
        });
379
380 1069 View Code Duplication
        $this->extend('url_generator', function ($generator, $app) {
381 1069
            $generators = [];
382
            if (isset($app['eccube.router.extend'])) {
383
                $generators[] = $app['eccube.router.extend'];
384 1069
            }
385 1069
            foreach ($app['eccube.routers.plugin'] as $router) {
386 1069
                $generators[] = $router;
387
            };
388
            $generators[] = $app['eccube.router.origin'];
389
            $generators[] = $generator;
390 1069
391
            return new ChainUrlGenerator($generators, $app['request_context']);
392 1069
        });
393 1069
394 1069
        // Route CollectionにEC-CUBEで定義したルーティングを追加(debug tool barに出力するため)
395 1069
        $this->extend('routes', function ($routes, $app) {
396
            if (isset($app['eccube.router.extend'])) {
397
                $routes->addCollection($app['eccube.router.extend']->getRouteCollection());
398 1069
            }
399 1069
            foreach ($app['eccube.routers.plugin'] as $router) {
400
                $routes->addCollection($router->getRouteCollection());
401
            };
402 1069
            $routes->addCollection($app['eccube.router.origin']->getRouteCollection());
403
404 1069
            return $routes;
405 1069
        });
406
407 1069
        // init http cache
408 1069
        $this->initCacheRequest();
409 1069
410 1069
        $this->initialized = true;
411
    }
412
413
    public function initLocale()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
414
    {
415
        // locale
416
        if (!empty($this['config']['locale'])) {
417 1069
            \Locale::setDefault($this['config']['locale']);
418
        };
419 1069
420
        // timezone
421
        if (!empty($this['config']['timezone'])) {
422
            date_default_timezone_set($this['config']['timezone']);
423
        }
424
425
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
426
            'locale' => $this['config']['locale'],
427 1069
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
428
            'locale_fallbacks' => ['ja', 'en'],
429 1069
        ));
430 1069
        $this->extend('translator', function ($translator, \Silex\Application $app) {
431
            $translator->addLoader('php', new \Symfony\Component\Translation\Loader\PhpFileLoader());
432
433 1069
            $file = __DIR__.'/Resource/locale/messages.'.$app['locale'].'.php';
434 1069
            if (file_exists($file)) {
435
                $translator->addResource('php', $file, $app['locale']);
436 1069
                $translator->addResource('php', $file, $app['locale'], 'validators');
437 1069
            }
438
439
            return $translator;
440 319
        });
441 319
    }
442 319
443 221
    public function initSession()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
444
    {
445 98
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
446
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
447
            'session.storage.options' => array(
448
                'name' => $this['config']['cookie_name'],
449 319
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
450 221
                'cookie_secure' => $this['config']['force_ssl'],
451 221
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
452
                'cookie_httponly' => true,
453 221
                // cookie_domainは指定しない
454 221
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
455 221
            ),
456
        ));
457
458 98
        $options = $this['config']['session_handler'];
459
460
        if ($options['enabled']) {
461
            // @see http://silex.sensiolabs.org/doc/providers/session.html#custom-session-configurations
462
            $this['session.storage.handler'] = null;
463
            ini_set('session.save_handler', $options['save_handler']);
464
            ini_set('session.save_path', $options['save_path']);
465 98
        }
466 98
    }
467
468 98
    public function initRendering()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
469 98
    {
470 98
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
471
            'twig.form.templates' => array('Form/form_layout.twig'),
472 319
        ));
473 319
        $this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
474
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
475
            $twig->addExtension(new \Twig_Extension_StringLoader());
476 319
477
            return $twig;
478 221
        });
479 221
480
        $this->before(function (Request $request, \Silex\Application $app) {
481
            $app['admin'] = $app['front'] = false;
482
            $pathinfo = rawurldecode($request->getPathInfo());
483
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
484
                $app['admin'] = true;
485 1069
            } else {
486
                $app['front'] = true;
487
            }
488
489
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
490
            if ($app->isAdminRequest()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Silex\Application as the method isAdminRequest() does only exist in the following sub-classes of Silex\Application: Eccube\Application, Eccube\InstallApplication. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
491 317
                if (file_exists(__DIR__.'/../../app/template/admin')) {
492 71
                    $paths[] = __DIR__.'/../../app/template/admin';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$paths was never initialized. Although not strictly required by PHP, it is generally a good practice to add $paths = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
493
                }
494
                $paths[] = $app['config']['template_admin_realdir'];
0 ignored issues
show
Bug introduced by
The variable $paths does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
495 317
                $paths[] = __DIR__.'/../../app/Plugin';
496
                $cacheDir =  __DIR__.'/../../app/cache/twig/admin';
497 317
            } else {
498
                // モバイル端末時、smartphoneディレクトリを探索パスに追加する.
499
                if ($app['mobile_detect.device_type'] == \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_SP) {
500 221
                    if (file_exists(__DIR__.'/../../app/template/smartphone')) {
501 221
                        $paths[] = __DIR__.'/../../app/template/smartphone';
502
                    }
503 221
                    $paths[] = __DIR__.'/Resource/template/smartphone';
504 221
                }
505
506 218
                if (file_exists($app['config']['template_realdir'])) {
507
                    $paths[] = $app['config']['template_realdir'];
508 218
                }
509 218
                $paths[] = $app['config']['template_default_realdir'];
510 218
                $paths[] = __DIR__.'/../../app/Plugin';
511
                $cacheDir =  __DIR__.'/../../app/cache/twig/'.$app['config']['template_code'];
512 3
            }
513
            $app['twig']->setCache($app['debug'] ? null : $cacheDir);
514
            $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
515 221
516
            // 管理画面のIP制限チェック.
517
            if ($app->isAdminRequest()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Silex\Application as the method isAdminRequest() does only exist in the following sub-classes of Silex\Application: Eccube\Application, Eccube\InstallApplication. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
518
                // IP制限チェック
519
                $allowHost = $app['config']['admin_allow_hosts'];
520 96
                if (count($allowHost) > 0) {
521 96
                    if (array_search($app['request_stack']->getCurrentRequest()->getClientIp(), $allowHost) === false) {
522
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
523
                    }
524 96
                }
525 2
            }
526 2
        }, self::EARLY_EVENT);
527
528 94
        // twigのグローバル変数を定義.
529
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) {
530
            // 未ログイン時にマイページや管理画面以下にアクセスするとSubRequestで実行されるため,
531
            // $event->isMasterRequest()ではなく、グローバル変数が初期化済かどうかの判定を行う
532
            if (isset($this['twig_global_initialized']) && $this['twig_global_initialized'] === true) {
533 96
                return;
534
            }
535
            // ショップ基本情報
536 96
            $this['twig']->addGlobal('BaseInfo', $this[BaseInfo::class]);
537
538
            if ($this->isAdminRequest()) {
539
                // 管理画面
540 96
                // 管理画面メニュー
541 96
                $menus = array('', '', '');
542 96
                $this['twig']->addGlobal('menus', $menus);
543 96
544 96
                $Member = $this->user();
545 96
                if (is_object($Member)) {
546 96
                    // ログインしていれば管理者のロールを取得
547 96
                    $AuthorityRoles = $this['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
548 96
549 96
                    $roles = array();
550 96
                    $request = $event->getRequest();
551 96
                    foreach ($AuthorityRoles as $AuthorityRole) {
552 96
                        // 管理画面でメニュー制御するため相対パス全てをセット
553 96
                        $roles[] = $request->getBaseUrl().'/'.$this['config']['admin_route'].$AuthorityRole->getDenyUrl();
554 96
                    }
555 34
556 34
                    $this['twig']->addGlobal('AuthorityRoles', $roles);
557
                }
558
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
559 96
            } else {
560 96
                // フロント画面
561
                $request = $event->getRequest();
562
                $route = $request->attributes->get('_route');
563 317
564 1069
                // ユーザ作成画面
565
                if ($route === 'user_data') {
566
                    $params = $request->attributes->get('_route_params');
567 1069
                    $route = $params['route'];
568
                    // プレビュー画面
569
                } elseif ($request->get('preview')) {
570
                    $route = 'preview';
571 1069
                }
572
573
                try {
574
                    $device_type_id = $this['mobile_detect.device_type'];
575
576
                    // TODO デバッグ用
577
                    if ($request->query->has('device_type_id')) {
578
                        $device_type_id = $request->get('device_type_id', \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
579
                    }
580
581
                    $DeviceType = $this['eccube.repository.master.device_type']
582 1069
                        ->find($device_type_id);
583 1069
                    $qb = $this['eccube.repository.page']->createQueryBuilder('p');
584
                    $Page = $qb->select('p, pll,l, bp, b')
585 1069
                        ->leftJoin('p.PageLayouts', 'pll')
586
                        ->leftJoin('pll.Layout', 'l')
587
                        ->leftJoin('l.BlockPositions', 'bp')
588
                        ->leftJoin('bp.Block', 'b')
589 1069
                        ->where('p.url = :route')
590 1069
                        ->andWhere('l.DeviceType = :DeviceType')
591
                        ->orderBy('bp.block_row', 'ASC')
592 1069
                        ->setParameter('route', $route)
593
                        ->setParameter('DeviceType', $DeviceType)
594
                        ->getQuery()
595
                        ->getSingleResult();
596
                } catch (\Doctrine\ORM\NoResultException $e) {
597 1069
                    $Page = $this['eccube.repository.page']->newPage($DeviceType);
0 ignored issues
show
Bug introduced by
The variable $DeviceType does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
598
                }
599 1069
600 1069
                $this['twig']->addGlobal('Page', $Page);
601
                $this['twig']->addGlobal('title', $Page->getName());
602 1069
            }
603
604
            $this['twig_global_initialized'] = true;
605 1069
        });
606
    }
607 1069
608
    public function initMailer()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
609 1069
    {
610 1069
611
        // メール送信時の文字エンコード指定(デフォルトはUTF-8)
612 1069
        if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
613 1069
            if ($this['config']['mail']['charset_iso_2022_jp'] === true) {
614
                \Swift::init(function () {
615
                    \Swift_DependencyContainer::getInstance()
616
                        ->register('mime.qpheaderencoder')
617 1069
                        ->asAliasOf('mime.base64headerencoder');
618 1069
                    \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
619 1069
                });
620 1069
            }
621
        }
622
623 1069
        $this->register(new \Silex\Provider\SwiftmailerServiceProvider());
624 1069
        $this['swiftmailer.options'] = $this['config']['mail'];
625 1069
626
        if (isset($this['config']['mail']['spool']) && is_bool($this['config']['mail']['spool'])) {
627
            $this['swiftmailer.use_spool'] = $this['config']['mail']['spool'];
628
        }
629
        // デフォルトはsmtpを使用
630
        $transport = $this['config']['mail']['transport'];
631
        if ($transport == 'sendmail') {
632
            $this['swiftmailer.transport'] = \Swift_SendmailTransport::newInstance();
633
        } elseif ($transport == 'mail') {
634
            $this['swiftmailer.transport'] = \Swift_MailTransport::newInstance();
635 1069
        }
636
    }
637
638
    public function initDoctrine()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
639
    {
640
        $this->register(new EntityEventServiceProvider());
641
        $this->register(new \Silex\Provider\DoctrineServiceProvider(), array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
642
            'dbs.options' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
643
                'default' => $this['config']['database'][$this['config']['database']['default']]
644 1069
            )
645 1069
        ));
646
        $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Provider\DoctrineOrmManagerRegistryProvider());
647 1069
648
        $app = $this;
649
        $this->extend('db.event_manager', function ($evm) use ($app) {
650
            $initSubscriber = new InitSubscriber($app);
651
            $evm->addEventSubscriber($initSubscriber);
652
653
            return $evm;
654
        });
655
656
        // UTCで保存
657
        // @see http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/cookbook/working-with-datetime.html
658
        UTCDateTimeType::setTimeZone($this['config']['timezone']);
659
        UTCDateTimeTzType::setTimeZone($this['config']['timezone']);
660
        Type::overrideType('datetime', UTCDateTimeType::class);
661
        Type::overrideType('datetimetz', UTCDateTimeTzType::class);
662
663
        // プラグインのmetadata定義を合わせて行う.
664
        $pluginConfigs = PluginConfigManager::getPluginConfigAll($this['debug']);
665
        $ormMappings = array();
666 1069
        $ormMappings[] = array(
667 1069
             'type' => 'annotation',
668
             'namespace' => 'Eccube\Entity',
669
             'path' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
670
                 __DIR__.'/Entity'
671
             ),
672
             'use_simple_annotation_reader' => false,
673
         );
674 1069
675 1069
        if (isset($this['config']['vendor_dir']) && file_exists($this['config']['vendor_dir'].'/Entity')) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
676 1069
677 1069
            $ormMappings[] = array(
678 1069
                'type' => 'annotation',
679 1069
                'namespace' => $this['config']['vendor_name'].'\Entity',
680
                'path' => array(
681
                    $this['config']['vendor_dir'].'/Entity',
682
                ),
683
                'use_simple_annotation_reader' => false,
684
            );
685
        }
686
687 1069
        foreach ($pluginConfigs as $code) {
688
            $config = $code['config'];
689
            // Doctrine Extend
690 1069
            if (isset($config['orm.path']) && is_array($config['orm.path'])) {
691
                // orm.pathが明示されている場合
692
                $paths = array();
693
                foreach ($config['orm.path'] as $path) {
694
                    $paths[] = $this['config']['plugin_realdir'].'/'.$config['code'].$path;
695
                }
696
                $ormMappings[] = array(
697
                    'type' => 'yml',
698
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
699
                    'path' => $paths,
700
                );
701
                $ormMappings[] = array(
702
                    'type' => 'annotation',
703
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
704
                    'path' => $paths,
705
                    'use_simple_annotation_reader' => false,
706
                );
707
            } else {
708
                // orm.pathを省略しても `/Resource/doctrine` と `/Entity` ディレクトリがある場合は設定を追加する
709
                $doctrineDir = $this['config']['plugin_realdir'].'/'.$config['code'].'/Resource/doctrine';
710 1069
                if (glob($doctrineDir.'/*.yml')) {
711 1069
                    $ormMappings[] = array(
712 1069
                        'type' => 'yml',
713
                        'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
714
                        'path' => [$doctrineDir],
715
                    );
716
                }
717
                $entityDir = $this['config']['plugin_realdir'].'/'.$config['code'].'/Entity';
718
                if (file_exists($entityDir)) {
719
                    $ormMappings[] = array(
720
                        'type' => 'annotation',
721 1069
                        'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
722 1069
                        'path' => [$entityDir],
723
                        'use_simple_annotation_reader' => false,
724
                    );
725
                }
726 1069
            }
727 1069
        }
728 1069
729 1069
        $options = array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
730 1069
            'mappings' => $ormMappings
731 1069
        );
732 1069
733 1069
        if (!$this['debug']) {
734 1069
            $cacheDrivers = array();
735 1069
            if (array_key_exists('doctrine_cache', $this['config'])) {
736 1069
                $cacheDrivers = $this['config']['doctrine_cache'];
737 1069
            }
738
739
            if (array_key_exists('metadata_cache', $cacheDrivers)) {
740
                $options['metadata_cache'] = $cacheDrivers['metadata_cache'];
741 1069
            }
742 1069
            if (array_key_exists('query_cache', $cacheDrivers)) {
743
                $options['query_cache'] = $cacheDrivers['query_cache'];
744
            }
745
            if (array_key_exists('result_cache', $cacheDrivers)) {
746
                $options['result_cache'] = $cacheDrivers['result_cache'];
747 1069
            }
748 1069
            if (array_key_exists('hydration_cache', $cacheDrivers)) {
749
                $options['hydration_cache'] = $cacheDrivers['hydration_cache'];
750
            }
751 1069
        }
752 1069
753
        $this->register(new \Dflydev\Provider\DoctrineOrm\DoctrineOrmServiceProvider(), array(
754
            'orm.proxies_dir' => __DIR__.'/../../app/cache/doctrine/proxies',
755 1069
            'orm.em.options' => $options,
756 1069
            'orm.custom.functions.string' => array(
757
                'NORMALIZE' => 'Eccube\Doctrine\ORM\Query\Normalize',
758
            ),
759 1069
            'orm.custom.functions.numeric' => array(
760 1069
                'EXTRACT' => 'Eccube\Doctrine\ORM\Query\Extract',
761 1069
            ),
762
        ));
763 1069
764 1069
        $this->extend(
765
            'orm.em.config',
766 1069
            function (\Doctrine\ORM\Configuration $config, \Silex\Application $app) {
767
768
                /** @var $chain \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain */
769
                $chain = $config->getMetadataDriverImpl();
770
                $drivers = $chain->getDrivers();
771
                foreach ($drivers as $namespace => $oldDriver) {
772
                    if ('Eccube\Entity' === $namespace) {
773
                        $newDriver = new AnnotationDriver(
774
                            $app['annotations'],
775
                            $oldDriver->getPaths());
776
                        $newDriver->setFileExtension($oldDriver->getFileExtension());
777
                        $newDriver->addExcludePaths($oldDriver->getExcludePaths());
778
                        $newDriver->setTraitProxiesDirectory(
779
                            realpath(__DIR__.'/../../app/proxy/entity'));
780
                        $chain->addDriver($newDriver, $namespace);
781
                    }
782
                }
783
784
                return $config;
785
            }
786
        );
787
788
        $this->extend('orm.em', function (\Doctrine\ORM\EntityManager $em, \Silex\Application $app) {
789
            // save
790 1069
            $saveEventSubscriber = new \Eccube\Doctrine\EventSubscriber\SaveEventSubscriber($app);
0 ignored issues
show
Compatibility introduced by
$app of type object<Silex\Application> is not a sub-type of object<Eccube\Application>. It seems like you assume a child class of the class Silex\Application to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
791
            $em->getEventManager()->addEventSubscriber($saveEventSubscriber);
792 1069
793 1069
            // load
794 1069
            $loadEventSubscriber = new \Eccube\Doctrine\EventSubscriber\LoadEventSubscriber($app);
0 ignored issues
show
Compatibility introduced by
$app of type object<Silex\Application> is not a sub-type of object<Eccube\Application>. It seems like you assume a child class of the class Silex\Application to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
795
            $em->getEventManager()->addEventSubscriber($loadEventSubscriber);
796 1069
797 1069
            // clear cache
798 1069
            $clearCacheEventSubscriber = new \Eccube\Doctrine\EventSubscriber\ClearCacheEventSubscriber($app);
0 ignored issues
show
Compatibility introduced by
$app of type object<Silex\Application> is not a sub-type of object<Eccube\Application>. It seems like you assume a child class of the class Silex\Application to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
799
            $em->getEventManager()->addEventSubscriber($clearCacheEventSubscriber);
800 1069
801 1069
            // filters
802 1069
            $config = $em->getConfiguration();
803 1069
            $config->addFilter("nostock_hidden", '\Eccube\Doctrine\Filter\NoStockHiddenFilter');
804
            $config->addFilter("incomplete_order_status_hidden", '\Eccube\Doctrine\Filter\OrderStatusFilter');
805
806
            return $em;
807
        });
808 1069
809 1069
        if (!$this['debug']) {
810
            // second level cacheの設定.
811 1069
            $this->extend(
812
                'orm.em.config',
813
                function (\Doctrine\ORM\Configuration $config, \Silex\Application $app) {
0 ignored issues
show
Unused Code introduced by
The parameter $app is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
814
                    $config->setSecondLevelCacheEnabled();
815 1069
                    $cacheConfig = $config->getSecondLevelCacheConfiguration();
816
                    $regionConfig = $cacheConfig->getRegionsConfiguration();
817
                    // TODO キャッシュ先は設定で切り替えられるように
818
                    $cache = $this['orm.cache.factory'](
819
                        'filesystem',
820
                        [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
821
                            'path' => __DIR__.'/../../app/cache/doctrine/second'
822
                        ]
823
                    );
824
                    $factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($regionConfig, $cache);
825
                    $cacheConfig->setCacheFactory($factory);
826
827
                    return $config;
828
                }
829 1069
            );
830 1069
        }
831
    }
832
833 1069
    public function initSecurity()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
834 1069
    {
835
        $this->register(new \Silex\Provider\SecurityServiceProvider());
836
        $this->register(new \Silex\Provider\CsrfServiceProvider());
837 1069
        $this->register(new \Silex\Provider\RememberMeServiceProvider());
838
839 1069
        $this['security.firewalls'] = array(
840
            'admin' => array(
841
                'pattern' => "^/{$this['config']['admin_route']}/",
842
                'form' => array(
843
                    'login_path' => "/{$this['config']['admin_route']}/login",
844 1069
                    'check_path' => "/{$this['config']['admin_route']}/login_check",
845
                    'username_parameter' => 'login_id',
846 1069
                    'password_parameter' => 'password',
847
                    'with_csrf' => true,
848
                    'use_forward' => true,
849
                ),
850 1069
                'logout' => array(
851 1069
                    'logout_path' => "/{$this['config']['admin_route']}/logout",
852 1069
                    'target_url' => "/{$this['config']['admin_route']}/",
853 1069
                ),
854 1069
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Member'),
855 1069
                'anonymous' => true,
856 1069
            ),
857
            'customer' => array(
858
                'pattern' => '^/',
859
                'form' => array(
860 1067
                    'login_path' => '/mypage/login',
861
                    'check_path' => '/login_check',
862
                    'username_parameter' => 'login_email',
863 1067
                    'password_parameter' => 'login_pass',
864 1067
                    'with_csrf' => true,
865 1067
                    'use_forward' => true,
866
                ),
867
                'logout' => array(
868
                    'logout_path' => '/logout',
869 1069
                    'target_url' => '/',
870
                ),
871
                'remember_me' => array(
872
                    'key' => sha1($this['config']['auth_magic']),
873
                    'name' => $this['config']['cookie_name'].'_rememberme',
874 1067
                    // lifetimeはデフォルトの1年間にする
875
                    // 'lifetime' => $this['config']['cookie_lifetime'],
876
                    'path' => $this['config']['root_urlpath'] ?: '/',
877
                    'secure' => $this['config']['force_ssl'],
878 1067
                    'httponly' => true,
879
                    'always_remember_me' => false,
880 1067
                    'remember_me_parameter' => 'login_memory',
881 1069
                ),
882
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Customer'),
883
                'anonymous' => true,
884 1067
            ),
885
        );
886
887 1069
        $channel = null;
888
        // 強制SSL
889
        if ($this['config']['force_ssl'] == \Eccube\Common\Constant::ENABLED) {
890
            $channel = "https";
891
        }
892
893 1069
        $this['security.access_rules'] = array(
894
            array("^/{$this['config']['admin_route']}/login", 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
895 1069
            array("^/{$this['config']['admin_route']}/", 'ROLE_ADMIN', $channel),
896 1069
            array('^/mypage/login', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
897
            array('^/mypage/withdraw_complete', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
898
            array('^/mypage/change', 'IS_AUTHENTICATED_FULLY', $channel),
899
            array('^/mypage', 'ROLE_USER', $channel),
900
        );
901 1069
902
        $this['eccube.password_encoder'] = function ($app) {
903
            return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
904
        };
905
        $this['security.encoder_factory'] = function ($app) {
906 1067
            return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
907
                'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
908 1067
                'Eccube\Entity\Member' => $app['eccube.password_encoder'],
909
            ));
910
        };
911 1067
        $this['eccube.event_listner.security'] = function ($app) {
912
            return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
913
        };
914 1067
915
        // Voterの設定
916
        $this['authority_voter'] = function ($app) {
917
            return new \Eccube\Security\Voter\AuthorityVoter($app);
918
        };
919 1067
920
        $this->extend('security.voters', function ($voters, \Silex\Application $app) {
921
            $voters[] = $app['authority_voter'];
922
923
            return $voters;
924
        });
925
926
        $this['security.access_manager'] = function ($app) {
927 1059
            return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
928
        };
929 1059
930
        $this->on(\Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN, array($this['eccube.event_listner.security'], 'onInteractiveLogin'));
931
    }
932
933
    /**
934
     * ロードバランサー、プロキシサーバの設定を行う
935
     */
936
    public function initProxy()
937 319
    {
938
        $config = $this['config'];
939 319
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
940
            $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($config) {
941
                // サブリクエストのREMOTE_ADDRも動的に設定を行う必要があるため、KernelEvents::REQUESTを使用する
942
                Request::setTrustedProxies(array_merge(array($event->getRequest()->server->get('REMOTE_ADDR')), $config['trusted_proxies']));
943
            }, self::EARLY_EVENT);
944 View Code Duplication
        } elseif (isset($config['trusted_proxies']) && !empty($config['trusted_proxies'])) {
945
            Request::setTrustedProxies($config['trusted_proxies']);
946
        }
947
    }
948
949
    public function initializePlugin()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
950
    {
951
        if ($this->initializedPlugin) {
952 1069
            return;
953
        }
954 1069
        $this->register(new ServiceProvider\EccubePluginServiceProvider());
955 1069
956
        // TODO Acme\ServiceProvider の初期化はここで OK?
957
        if (array_key_exists('service',$this['config'])) {
0 ignored issues
show
introduced by
Add a single space after each comma delimiter
Loading history...
958
            foreach ($this['config']['service'] as $service) {
959
                $this->register(new $service);
0 ignored issues
show
introduced by
Use parentheses when instantiating classes
Loading history...
960
            }
961
        }
962
        $this->initializedPlugin = true;
963
    }
964
965
    /**
966
     * PHPUnit を実行中かどうかを設定する.
967
     *
968
     * @param boolean $testMode PHPUnit を実行中の場合 true
969
     */
970
    public function setTestMode($testMode)
971
    {
972
        $this->testMode = $testMode;
973
    }
974
975
    /**
976
     * PHPUnit を実行中かどうか.
977
     *
978
     * @return boolean PHPUnit を実行中の場合 true
979
     */
980
    public function isTestMode()
981
    {
982
        return $this->testMode;
983
    }
984
985
    /**
986
     *
987
     * データベースの接続を確認
988
     * 成功 : trueを返却
989
     * 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
990 1070
     * 備考 : app['debug']がtrueの際は処理を行わない
991
     *
992 1070
     * @return boolean true
993 1070
     *
994
     */
995 1070
    protected function checkDatabaseConnection()
996 1070
    {
997 1070
        if ($this['debug']) {
998 1070
            return;
999
        }
1000
        try {
1001
            $this['db']->connect();
1002 1070
        } catch (\Doctrine\DBAL\DBALException $e) {
1003
            $this['monolog']->error($e->getMessage());
1004 1070
            $this['twig.path'] = array(__DIR__.'/Resource/template/exception');
1005 1070
            $html = $this['twig']->render('error.twig', array(
1006
                'error_title' => 'データーベース接続エラー',
1007 1070
                'error_message' => 'データーベースを確認してください',
1008 1070
            ));
1009
            $response = new Response();
1010
            $response->setContent($html);
1011
            $response->setStatusCode('500');
1012 1070
            $response->headers->set('Content-Type', 'text/html');
1013 1070
            $response->send();
1014
            die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method checkDatabaseConnection() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1015 1070
        }
1016 1070
1017
        return true;
1018 1070
    }
1019
1020
    /**
1021 1070
     * Config ファイルをパースし、連想配列を返します.
1022
     *
1023
     * $config_name.yml ファイルをパースし、連想配列を返します.
1024
     * $config_name.php が存在する場合は、 PHP ファイルに記述された連想配列を使用します。
1025
     *
1026
     * @param string $config_name Config 名称
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
1027
     * @param array $configAll Config の連想配列
0 ignored issues
show
introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
1028
     * @param boolean $wrap_key Config の連想配列に config_name のキーを生成する場合 true, デフォルト false
0 ignored issues
show
introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
1029
     * @param string $ymlPath config yaml を格納したディレクトリ
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
1030 1069
     * @param string $distPath config yaml dist を格納したディレクトリ
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
1031
     * @return Application
1032 1069
     */
1033 1069
    public function parseConfig($config_name, array &$configAll, $wrap_key = false, $ymlPath = null, $distPath = null)
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
1034 1069
    {
1035
        $ymlPath = $ymlPath ? $ymlPath : __DIR__.'/../../app/config/eccube';
1036
        $distPath = $distPath ? $distPath : __DIR__.'/../../src/Eccube/Resource/config';
1037
1038
        $config = [];
1039
        $config_php = $ymlPath.'/'.$config_name.'.php';
1040
        if (file_exists($config_php)) {
1041
            $config = require $config_php;
1042
        }
1043
1044
        // `%ROOT_DIR%`を絶対パスに変換
1045
        $rootDir = realpath(__DIR__.'/../../');
1046 1069
        array_walk($config, function(&$value) use ($rootDir) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
1047
            $value = str_replace('%ROOT_DIR%', $rootDir, $value);
1048
        });
1049 1069
1050 1069
        $config_php_dist = $distPath.'/'.$config_name.'.php';
1051
        $config_dist = require $config_php_dist;
1052
1053
        // `%ROOT_DIR%`を絶対パスに変換
1054
        array_walk($config_dist, function(&$value) use ($rootDir) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
1055
            $value = str_replace('%ROOT_DIR%', $rootDir, $value);
1056
        });
1057
1058
        if ($wrap_key) {
1059
            $configAll = array_replace_recursive($configAll, array($config_name => $config_dist), array($config_name => $config));
1060
        } else {
1061
            $configAll = array_replace_recursive($configAll, $config_dist, $config);
1062
        }
1063
1064
        return $this;
1065
    }
1066
1067
    /**
1068
     * セッションが開始されているかどうか.
1069
     *
1070
     * @return boolean セッションが開始済みの場合 true
1071
     * @link http://php.net/manual/ja/function.session-status.php#113468
1072
     */
1073
    protected function isSessionStarted()
1074
    {
1075
        if (php_sapi_name() !== 'cli') {
1076
            if (version_compare(phpversion(), '5.4.0', '>=')) {
1077
                return session_status() === PHP_SESSION_ACTIVE ? true : false;
1078
            } else {
1079
                return session_id() === '' ? false : true;
1080
            }
1081
        }
1082
1083
        return false;
1084
    }
1085
1086
    /**
1087
     * Http Cache対応
1088
     */
1089
    protected function initCacheRequest()
1090
    {
1091
        // httpキャッシュが無効の場合はイベント設定を行わない.
1092
        if (!$this['config']['http_cache']['enabled']) {
1093
            return;
1094
        }
1095
1096
        $app = $this;
1097
1098
        // Response Event(http cache対応、event実行は一番遅く設定)
1099
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
1100
1101
            if (!$event->isMasterRequest()) {
1102
                return;
1103
            }
1104
1105
            $request = $event->getRequest();
1106
            $response = $event->getResponse();
1107
1108
            $route = $request->attributes->get('_route');
1109
1110
            $etag = md5($response->getContent());
1111
1112
            if (strpos($route, 'admin') === 0) {
1113
                // 管理画面
1114
1115
                // 管理画面ではコンテンツの中身が変更された時点でキャッシュを更新し、キャッシュの適用範囲はprivateに設定
1116
                $response->setCache(array(
1117
                    'etag' => $etag,
1118
                    'private' => true,
1119
                ));
1120
1121
                if ($response->isNotModified($request)) {
1122
                    return $response;
1123
                }
1124
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1125
            } else {
1126
                // フロント画面
1127
                $cacheRoute = $app['config']['http_cache']['route'];
1128
1129
                if (in_array($route, $cacheRoute) === true) {
1130
                    // キャッシュ対象となる画面lが含まれていた場合、キャッシュ化
1131
                    // max-ageを設定しているためExpiresは不要
1132
                    // Last-Modifiedだと比較する項目がないためETagで対応
1133
                    // max-ageを設定していた場合、contentの中身が変更されても変更されない
1134
1135
                    $age = $app['config']['http_cache']['age'];
1136
1137
                    $response->setCache(array(
1138
                        'etag' => $etag,
1139
                        'max_age' => $age,
1140
                        's_maxage' => $age,
1141
                        'public' => true,
1142
                    ));
1143
1144
                    if ($response->isNotModified($request)) {
1145
                        return $response;
1146
                    }
1147
                }
1148
            }
1149
1150
        }, -1024);
1151
    }
1152
}
1153