Failed Conditions
Push — experimental/3.1 ( 36d064...2457e2 )
by Kiyotaka
128:07 queued 120:55
created

Application   F

Complexity

Total Complexity 108

Size/Duplication

Total Lines 1055
Duplicated Lines 2.37 %

Coupling/Cohesion

Components 2
Dependencies 91

Test Coverage

Coverage 76.35%

Importance

Changes 0
Metric Value
dl 25
loc 1055
rs 0.7564
c 0
b 0
f 0
ccs 397
cts 520
cp 0.7635
wmc 108
lcom 2
cbo 91

22 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 8 2
A clearInstance() 0 4 1
A __clone() 0 4 1
A __construct() 0 14 2
A isBooted() 0 4 1
A initLogger() 0 5 1
C initialize() 22 222 12
B initLocale() 0 29 5
B initSession() 0 24 3
D initRendering() 0 139 20
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 initConfig() 0 25 2
C initMailer() 0 29 8
F initDoctrine() 0 192 16
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 Doctrine\DBAL\Types\Type;
27
use Eccube\Di\Scanner\ComponentScanner;
28
use Eccube\Di\Scanner\EntityEventScanner;
29
use Eccube\Di\Scanner\FormExtensionScanner;
30
use Eccube\Di\Scanner\FormTypeScanner;
31
use Eccube\Di\Scanner\QueryExtensionScanner;
32
use Eccube\Di\Scanner\RepositoryScanner;
33
use Eccube\Di\Scanner\ServiceScanner;
34
use Eccube\Doctrine\DBAL\Types\UTCDateTimeType;
35
use Eccube\Doctrine\DBAL\Types\UTCDateTimeTzType;
36
use Eccube\Doctrine\EventSubscriber\InitSubscriber;
37
use Eccube\Doctrine\ORM\Mapping\Driver\AnnotationDriver;
38
use Eccube\Entity\BaseInfo;
39
use Eccube\Plugin\ConfigManager as PluginConfigManager;
40
use Eccube\Routing\EccubeRouter;
41
use Eccube\ServiceProvider\CompatRepositoryProvider;
42
use Eccube\ServiceProvider\CompatServiceProvider;
43
use Eccube\ServiceProvider\DiServiceProvider;
44
use Eccube\ServiceProvider\EntityEventServiceProvider;
45
use Eccube\ServiceProvider\MobileDetectServiceProvider;
46
use Eccube\ServiceProvider\TwigLintServiceProvider;
47
use Sergiors\Silex\Routing\ChainUrlGenerator;
48
use Sergiors\Silex\Routing\ChainUrlMatcher;
49
use Symfony\Component\Dotenv\Dotenv;
50
use Symfony\Component\HttpFoundation\Request;
51
use Symfony\Component\HttpFoundation\Response;
52
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
53
use Symfony\Component\HttpKernel\KernelEvents;
54
55
class Application extends \Silex\Application
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
56
{
57
    use \Silex\Application\FormTrait;
58
    use \Silex\Application\UrlGeneratorTrait;
59
    use \Silex\Application\MonologTrait;
60
    use \Silex\Application\SwiftmailerTrait;
61
    use \Silex\Application\SecurityTrait;
62
    use \Silex\Application\TranslationTrait;
63
    use \Eccube\Application\ApplicationTrait;
64
    use \Eccube\Application\SecurityTrait;
65
    use \Eccube\Application\TwigTrait;
66
67
    protected static $instance;
68
69
    protected $initialized = false;
70
    protected $initializedPlugin = false;
71
    protected $testMode = false;
72
73 1067
    public static function getInstance(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
74
    {
75 1067
        if (!is_object(self::$instance)) {
76 1067
            self::$instance = new Application($values);
77
        }
78
79 1067
        return self::$instance;
80
    }
81
82 1067
    public static function clearInstance()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
83
    {
84 1067
        self::$instance = null;
85
    }
86
87
    final public function __clone()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
88
    {
89
        throw new \Exception('Clone is not allowed against '.get_class($this));
90
    }
91
92 1068
    public function __construct(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
93
    {
94 1068
        parent::__construct($values);
95
96 1068
        if (is_null(self::$instance)) {
97 1068
            self::$instance = $this;
98
        }
99
100
        // load config
101 1068
        $this->initConfig();
102
103
        // init monolog
104 1068
        $this->initLogger();
105
    }
106
107
    /**
108
     * Application::runが実行されているか親クラスのプロパティから判定
109
     *
110
     * @return bool
111
     */
112 1067
    public function isBooted()
113
    {
114 1067
        return $this->booted;
115
    }
116
117 1068
    public function initConfig()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
118
    {
119
        // load .env
120 1068
        $envFile = __DIR__.'/../../app/config/eccube/.env';
121 1068
        if (file_exists($envFile)) {
122 1068
            (new Dotenv())->load($envFile);
123
        }
124
125
        // load config
126
        $this['config'] = function() {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
127 1068
            $configAll = array();
128 1068
            $this->parseConfig('constant', $configAll)
129 1068
                ->parseConfig('path', $configAll)
130 1068
                ->parseConfig('config', $configAll)
131 1068
                ->parseConfig('database', $configAll)
132 1068
                ->parseConfig('mail', $configAll)
133 1068
                ->parseConfig('log', $configAll)
134 1068
                ->parseConfig('nav', $configAll, true)
135 1068
                ->parseConfig('doctrine_cache', $configAll)
136 1068
                ->parseConfig('http_cache', $configAll)
137 1068
                ->parseConfig('session_handler', $configAll);
138
139 1068
            return $configAll;
140
        };
141
    }
142
143 1068
    public function initLogger()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
144
    {
145 1068
        $app = $this;
146 1068
        $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...
147
    }
148
149 1067
    public function initialize()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
150
    {
151 1067
        if ($this->initialized) {
152 2
            return;
153
        }
154
155
        // init locale
156 1067
        $this->initLocale();
157
158
        // init session
159 1067
        if (!$this->isSessionStarted()) {
160 1067
            $this->initSession();
161
        }
162
163
        // init twig
164 1067
        $this->initRendering();
165
166
        // init provider
167 1067
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
168 1067
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
169
        ));
170 1067
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
171 1067
        $this->register(new \Silex\Provider\FormServiceProvider());
172 1067
        $this->register(new \Silex\Provider\SerializerServiceProvider());
173 1067
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
174 1067
        $this->register(new \Saxulum\Validator\Provider\SaxulumValidatorProvider());
175 1067
        $this->register(new MobileDetectServiceProvider());
176 1067
        $this->register(new TwigLintServiceProvider());
177
178
        $this->error(function (\Exception $e, Request $request, $code) {
179 25
            if ($this['debug']) {
180 25
                return;
181
            }
182
183
            switch ($code) {
184
                case 403:
185
                    $title = 'アクセスできません。';
186
                    $message = 'お探しのページはアクセスができない状況にあるか、移動もしくは削除された可能性があります。';
187
                    break;
188
                case 404:
189
                    $title = 'ページがみつかりません。';
190
                    $message = 'URLに間違いがないかご確認ください。';
191
                    break;
192
                default:
193
                    $title = 'システムエラーが発生しました。';
194
                    $message = '大変お手数ですが、サイト管理者までご連絡ください。';
195
                    break;
196
            }
197
198
            return $this->render('error.twig', array(
199
                'error_title' => $title,
200
                'error_message' => $message,
201
            ));
202 1067
        });
203
204
        // init mailer
205 1067
        $this->initMailer();
206
207 1067
        $this->register(new \Sergiors\Silex\Provider\DoctrineCacheServiceProvider());
208 1067
        $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...
209 1067
            'annotations.debug' => $this['debug'],
210
            'annotations.options' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
211 1067
                'cache_driver' => $this['debug'] ? 'array' : 'filesystem',
212 1067
                'cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/annotation'
213
            ]
214
        ]);
215
216
        // init doctrine orm
217 1067
        $this->initDoctrine();
218
219
        // Set up the DBAL connection now to check for a proper connection to the database.
220 1067
        $this->checkDatabaseConnection();
221
222
        // init security
223 1067
        $this->initSecurity();
224
225 1067
        $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...
226 1067
            'routing.cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/routing'
227
        ]);
228 1067
        $this->register(new \Sergiors\Silex\Provider\TemplatingServiceProvider());
229 1067
        $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...
230 1067
            'request' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
231
                'auto_convert' => true
232
            ]
233
        ]);
234
        // init proxy
235 1067
        $this->initProxy();
236
237 1067
        $enabledPlugins = $this['orm.em']->getRepository('Eccube\Entity\Plugin')->findAllEnabled();
238 1067
        $configRootDir = $this['config']['root_dir'];
239
        $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...
240
            return $configRootDir.'/app/Plugin/'.$plugin->getCode();
241 1067
        }, $enabledPlugins);
242
243
        $pluginSubDirs = (function($dirName) use ($enabledPluginDirs) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
244
            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...
245
                return $pluginDir . '/' . $dirName;
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
246 1067
            }, $enabledPluginDirs);
247 1067
        });
248
249
        // init ec-cube service provider
250 1067
        $this->register(new DiServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
251
            'eccube.di.scanners' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
252 1067
                new ComponentScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
253 1067
                    $this['config']['root_dir'].'/app/Acme/Controller',
254 1067
                    $this['config']['root_dir'].'/src/Eccube/Controller'
255 1067
                ], $pluginSubDirs('Controller'))),
256 1067
                new FormTypeScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
257 1067
                    $this['config']['root_dir'].'/src/Eccube/Form/Type'
258 1067
                ], $pluginSubDirs('Form/Type'))),
259 1067
                new FormExtensionScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
260 1067
                    $this['config']['root_dir'].'/src/Eccube/Form/Extension'
261 1067
                ], $pluginSubDirs('Form/Extension'))),
262 1067
                new ServiceScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
263 1067
                    $this['config']['root_dir'].'/src/Eccube/Service'
264 1067
                ], $pluginSubDirs('Service'))),
265 1067
                new RepositoryScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
266 1067
                    $this['config']['root_dir'].'/src/Eccube/Repository'
267 1067
                ], $pluginSubDirs('Repository'))),
268 1067
                new QueryExtensionScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
269 1067
                    $this['config']['root_dir'].'/src/Eccube/Repository'
270 1067
                ], $pluginSubDirs('Repository'))),
271 1067
                new EntityEventScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
272 1067
                    $this['config']['root_dir'].'/app/Acme/Entity'
273 1067
                ], $pluginSubDirs('Entity')))
274
            ],
275 1067
            'eccube.di.generator.dir' => $this['config']['root_dir'].'/app/cache/provider'
276
        ]);
277
278 1067
        $this->register(new CompatRepositoryProvider());
279 1067
        $this->register(new CompatServiceProvider());
280 1067
        $this->register(new ServiceProvider\EccubeServiceProvider());
281
282 1067
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
283 1067
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
284
285
        // ルーティングの設定
286
        // TODO EccubeRoutingServiceProviderに移植する.
287 1067
        $app = $this;
288
        $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...
289
            $options = [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
290 1067
                'debug' => $app['debug'],
291 1067
                'cache_dir' => $app['routing.cache_dir'],
292 1067
                'matcher_base_class' => $app['request_matcher_class'],
293 1067
                'matcher_class' => $app['request_matcher_class'],
294 1067
                'matcher_cache_class' => $cachePrefix.'UrlMatcher',
295 1067
                'generator_cache_class' => $cachePrefix.'UrlGenerator'
296
            ];
297 1067
            $router = new EccubeRouter(
298 1067
                $app['routing.loader'],
299 1067
                $resoure,
300 1067
                $options,
301 1067
                $app['request_context'],
302 1067
                $app['logger']
303
            );
304
305 1067
            $router->setAdminPrefix($app['config']['admin_route']);
306 1067
            $router->setUserDataPrefix($app['config']['user_data_route']);
307 1067
            $router->setRequireHttps($app['config']['force_ssl']);
308
309 1067
            return $router;
310 1067
        });
311
312
        $this['eccube.router.origin'] = function ($app) {
313 1067
            $resource = __DIR__.'/Controller';
314 1067
            $cachePrefix = 'Origin';
315
316 1067
            return $app['eccube.router']($resource, $cachePrefix);
317
        };
318
319 1067
        $this['eccube.routers.plugin'] = [];
320
321
        $this['eccube.router.extend'] = function ($app) {
322
            // TODO ディレクトリ名は暫定
323 1067
            $resource = $app['config']['root_dir'].'/app/Acme/Controller';
324 1067
            $cachePrefix = 'Extend';
325
326 1067
            $router = $app['eccube.router']($resource, $cachePrefix);
327
328 1067
            return $router;
329
        };
330
331 View Code Duplication
        $this->extend('request_matcher', function ($matcher, $app) {
332 1067
            $matchers = [];
333 1067
            $matchers[] = $app['eccube.router.extend'];
334 1067
            foreach ($app['eccube.routers.plugin'] as $router) {
335
                $matchers[] = $router;
336
            };
337 1067
            $matchers[] = $app['eccube.router.origin'];
338 1067
            $matchers[] = $matcher;
339
340 1067
            return new ChainUrlMatcher($matchers, $app['request_context']);
341 1067
        });
342
343 View Code Duplication
        $this->extend('url_generator', function ($generator, $app) {
344 1067
            $generators = [];
345 1067
            $generators[] = $app['eccube.router.extend'];
346 1067
            foreach ($app['eccube.routers.plugin'] as $router) {
347
                $generators[] = $router;
348
            };
349 1067
            $generators[] = $app['eccube.router.origin'];
350 1067
            $generators[] = $generator;
351
352 1067
            return new ChainUrlGenerator($generators, $app['request_context']);
353 1067
        });
354
355
        // Route CollectionにEC-CUBEで定義したルーティングを追加(debug tool barに出力するため)
356
        $this->extend('routes', function ($routes, $app) {
357 1067
            $routes->addCollection($app['eccube.router.extend']->getRouteCollection());
358 1067
            foreach ($app['eccube.routers.plugin'] as $router) {
359
                $routes->addCollection($router->getRouteCollection());
360
            };
361 1067
            $routes->addCollection($app['eccube.router.origin']->getRouteCollection());
362
363 1067
            return $routes;
364 1067
        });
365
366
        // init http cache
367 1067
        $this->initCacheRequest();
368
369 1067
        $this->initialized = true;
370
    }
371
372 1067
    public function initLocale()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
373
    {
374
        // locale
375 1067
        if (!empty($this['config']['locale'])) {
376 1067
            \Locale::setDefault($this['config']['locale']);
377
        };
378
379
        // timezone
380 1067
        if (!empty($this['config']['timezone'])) {
381 1067
            date_default_timezone_set($this['config']['timezone']);
382
        }
383
384 1067
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
385 1067
            'locale' => $this['config']['locale'],
386 1067
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
387
            'locale_fallbacks' => ['ja', 'en'],
388
        ));
389
        $this->extend('translator', function ($translator, \Silex\Application $app) {
390 1067
            $translator->addLoader('php', new \Symfony\Component\Translation\Loader\PhpFileLoader());
391
392 1067
            $file = __DIR__.'/Resource/locale/messages.'.$app['locale'].'.php';
393 1067
            if (file_exists($file)) {
394 1067
                $translator->addResource('php', $file, $app['locale']);
395 1067
                $translator->addResource('php', $file, $app['locale'], 'validators');
396
            }
397
398 1067
            return $translator;
399 1067
        });
400
    }
401
402 1067
    public function initSession()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
403
    {
404 1067
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
405 1067
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
406
            'session.storage.options' => array(
407 1067
                'name' => $this['config']['cookie_name'],
408 1067
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
409 1067
                'cookie_secure' => $this['config']['force_ssl'],
410 1067
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
411
                'cookie_httponly' => true,
412
                // cookie_domainは指定しない
413
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
414
            ),
415
        ));
416
417 1067
        $options = $this['config']['session_handler'];
418
419 1067
        if ($options['enabled']) {
420
            // @see http://silex.sensiolabs.org/doc/providers/session.html#custom-session-configurations
421
            $this['session.storage.handler'] = null;
422
            ini_set('session.save_handler', $options['save_handler']);
423
            ini_set('session.save_path', $options['save_path']);
424
        }
425
    }
426
427 1067
    public function initRendering()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
428
    {
429 1067
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
430 1067
            'twig.form.templates' => array('Form/form_layout.twig'),
431
        ));
432
        $this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
433 1067
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
434 1067
            $twig->addExtension(new \Twig_Extension_StringLoader());
435
436 1067
            return $twig;
437 1067
        });
438
439
        $this->before(function (Request $request, \Silex\Application $app) {
440 319
            $app['admin'] = $app['front'] = false;
441 319
            $pathinfo = rawurldecode($request->getPathInfo());
442 319
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
443 221
                $app['admin'] = true;
444
            } else {
445 98
                $app['front'] = true;
446
            }
447
448
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
449 319
            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...
450 221
                if (file_exists(__DIR__.'/../../app/template/admin')) {
451 221
                    $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...
452
                }
453 221
                $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...
454 221
                $paths[] = __DIR__.'/../../app/Plugin';
455 221
                $cacheDir =  __DIR__.'/../../app/cache/twig/admin';
456
            } else {
457
                // モバイル端末時、smartphoneディレクトリを探索パスに追加する.
458 98
                if ($app['mobile_detect.device_type'] == \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_SP) {
459
                    if (file_exists(__DIR__.'/../../app/template/smartphone')) {
460
                        $paths[] = __DIR__.'/../../app/template/smartphone';
461
                    }
462
                    $paths[] = __DIR__.'/Resource/template/smartphone';
463
                }
464
465 98
                if (file_exists($app['config']['template_realdir'])) {
466 98
                    $paths[] = $app['config']['template_realdir'];
467
                }
468 98
                $paths[] = $app['config']['template_default_realdir'];
469 98
                $paths[] = __DIR__.'/../../app/Plugin';
470 98
                $cacheDir =  __DIR__.'/../../app/cache/twig/'.$app['config']['template_code'];
471
            }
472 319
            $app['twig']->setCache($app['debug'] ? null : $cacheDir);
473 319
            $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
474
475
            // 管理画面のIP制限チェック.
476 319
            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...
477
                // IP制限チェック
478 221
                $allowHost = $app['config']['admin_allow_hosts'];
479 221
                if (count($allowHost) > 0) {
480
                    if (array_search($app['request_stack']->getCurrentRequest()->getClientIp(), $allowHost) === false) {
481
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
482
                    }
483
                }
484
            }
485 1067
        }, self::EARLY_EVENT);
486
487
        // twigのグローバル変数を定義.
488
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) {
489
            // 未ログイン時にマイページや管理画面以下にアクセスするとSubRequestで実行されるため,
490
            // $event->isMasterRequest()ではなく、グローバル変数が初期化済かどうかの判定を行う
491 317
            if (isset($this['twig_global_initialized']) && $this['twig_global_initialized'] === true) {
492 71
                return;
493
            }
494
            // ショップ基本情報
495 317
            $this['twig']->addGlobal('BaseInfo', $this[BaseInfo::class]);
496
497 317
            if ($this->isAdminRequest()) {
498
                // 管理画面
499
                // 管理画面メニュー
500 221
                $menus = array('', '', '');
501 221
                $this['twig']->addGlobal('menus', $menus);
502
503 221
                $Member = $this->user();
504 221
                if (is_object($Member)) {
505
                    // ログインしていれば管理者のロールを取得
506 218
                    $AuthorityRoles = $this['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
507
508 218
                    $roles = array();
509 218
                    $request = $event->getRequest();
510 218
                    foreach ($AuthorityRoles as $AuthorityRole) {
511
                        // 管理画面でメニュー制御するため相対パス全てをセット
512 3
                        $roles[] = $request->getBaseUrl().'/'.$this['config']['admin_route'].$AuthorityRole->getDenyUrl();
513
                    }
514
515 221
                    $this['twig']->addGlobal('AuthorityRoles', $roles);
516
                }
517
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
518
            } else {
519
                // フロント画面
520 96
                $request = $event->getRequest();
521 96
                $route = $request->attributes->get('_route');
522
523
                // ユーザ作成画面
524 96
                if ($route === 'user_data') {
525 2
                    $params = $request->attributes->get('_route_params');
526 2
                    $route = $params['route'];
527
                    // プレビュー画面
528 94
                } elseif ($request->get('preview')) {
529
                    $route = 'preview';
530
                }
531
532
                try {
533 96
                    $device_type_id = $this['mobile_detect.device_type'];
534
535
                    // TODO デバッグ用
536 96
                    if ($request->query->has('device_type_id')) {
537
                        $device_type_id = $request->get('device_type_id', \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
538
                    }
539
540 96
                    $DeviceType = $this['eccube.repository.master.device_type']
541 96
                        ->find($device_type_id);
542 96
                    $qb = $this['eccube.repository.page']->createQueryBuilder('p');
543 96
                    $Page = $qb->select('p, pll,l, bp, b')
544 96
                        ->leftJoin('p.PageLayouts', 'pll')
545 96
                        ->leftJoin('pll.Layout', 'l')
546 96
                        ->leftJoin('l.BlockPositions', 'bp')
547 96
                        ->leftJoin('bp.Block', 'b')
548 96
                        ->where('p.url = :route')
549 96
                        ->andWhere('l.DeviceType = :DeviceType')
550 96
                        ->orderBy('bp.block_row', 'ASC')
551 96
                        ->setParameter('route', $route)
552 96
                        ->setParameter('DeviceType', $DeviceType)
553 96
                        ->getQuery()
554 96
                        ->getSingleResult();
555 34
                } catch (\Doctrine\ORM\NoResultException $e) {
556 34
                    $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...
557
                }
558
559 96
                $this['twig']->addGlobal('Page', $Page);
560 96
                $this['twig']->addGlobal('title', $Page->getName());
561
            }
562
563 317
            $this['twig_global_initialized'] = true;
564 1067
        });
565
    }
566
567 1067
    public function initMailer()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
568
    {
569
570
        // メール送信時の文字エンコード指定(デフォルトはUTF-8)
571 1067
        if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
572
            if ($this['config']['mail']['charset_iso_2022_jp'] === true) {
573
                \Swift::init(function () {
574
                    \Swift_DependencyContainer::getInstance()
575
                        ->register('mime.qpheaderencoder')
576
                        ->asAliasOf('mime.base64headerencoder');
577
                    \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
578
                });
579
            }
580
        }
581
582 1067
        $this->register(new \Silex\Provider\SwiftmailerServiceProvider());
583 1067
        $this['swiftmailer.options'] = $this['config']['mail'];
584
585 1067
        if (isset($this['config']['mail']['spool']) && is_bool($this['config']['mail']['spool'])) {
586
            $this['swiftmailer.use_spool'] = $this['config']['mail']['spool'];
587
        }
588
        // デフォルトはsmtpを使用
589 1067
        $transport = $this['config']['mail']['transport'];
590 1067
        if ($transport == 'sendmail') {
591
            $this['swiftmailer.transport'] = \Swift_SendmailTransport::newInstance();
592 1067
        } elseif ($transport == 'mail') {
593
            $this['swiftmailer.transport'] = \Swift_MailTransport::newInstance();
594
        }
595
    }
596
597 1067
    public function initDoctrine()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
598
    {
599 1067
        $this->register(new EntityEventServiceProvider());
600 1067
        $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...
601
            'dbs.options' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
602 1067
                'default' => $this['config']['database'][$this['config']['database']['default']]
603
            )
604
        ));
605 1067
        $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Provider\DoctrineOrmManagerRegistryProvider());
606
607 1067
        $app = $this;
608
        $this->extend('db.event_manager', function ($evm) use ($app) {
609 1067
            $initSubscriber = new InitSubscriber($app);
610 1067
            $evm->addEventSubscriber($initSubscriber);
611
612 1067
            return $evm;
613 1067
        });
614
615
        // UTCで保存
616
        // @see http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/cookbook/working-with-datetime.html
617 1067
        UTCDateTimeType::setTimeZone($this['config']['timezone']);
618 1067
        UTCDateTimeTzType::setTimeZone($this['config']['timezone']);
619 1067
        Type::overrideType('datetime', UTCDateTimeType::class);
620 1067
        Type::overrideType('datetimetz', UTCDateTimeTzType::class);
621
622
        // プラグインのmetadata定義を合わせて行う.
623 1067
        $pluginConfigs = PluginConfigManager::getPluginConfigAll($this['debug']);
624 1067
        $ormMappings = array();
625 1067
        $ormMappings[] = array(
626
             'type' => 'annotation',
627
             'namespace' => 'Eccube\Entity',
628
             'path' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
629
                 __DIR__.'/Entity'
630
             ),
631
             'use_simple_annotation_reader' => false,
632
         );
633
634
        // TODO namespace は暫定
635 1067
        $ormMappings[] = array(
636
            'type' => 'annotation',
637
            'namespace' => 'Acme\Entity',
638
            'path' => array(
639
                __DIR__.'/../../app/Acme/Entity',
640
            ),
641
            'use_simple_annotation_reader' => false,
642
        );
643
644 1067
        foreach ($pluginConfigs as $code) {
645 1067
            $config = $code['config'];
646
            // Doctrine Extend
647 1067
            if (isset($config['orm.path']) && is_array($config['orm.path'])) {
648
                // orm.pathが明示されている場合
649
                $paths = array();
650
                foreach ($config['orm.path'] as $path) {
651
                    $paths[] = $this['config']['plugin_realdir'].'/'.$config['code'].$path;
652
                }
653
                $ormMappings[] = array(
654
                    'type' => 'yml',
655
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
656
                    'path' => $paths,
657
                );
658
                $ormMappings[] = array(
659
                    'type' => 'annotation',
660
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
661
                    'path' => $paths,
662
                    'use_simple_annotation_reader' => false,
663
                );
664
            } else {
665
                // orm.pathを省略しても `/Resource/doctrine` と `/Entity` ディレクトリがある場合は設定を追加する
666 1067
                $doctrineDir = $this['config']['plugin_realdir'].'/'.$config['code'].'/Resource/doctrine';
667 1067
                if (glob($doctrineDir.'/*.yml')) {
668
                    $ormMappings[] = array(
669
                        'type' => 'yml',
670
                        'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
671
                        'path' => [$doctrineDir],
672
                    );
673
                }
674 1067
                $entityDir = $this['config']['plugin_realdir'].'/'.$config['code'].'/Entity';
675 1067
                if (file_exists($entityDir)) {
676 1067
                    $ormMappings[] = array(
677 1067
                        'type' => 'annotation',
678 1067
                        'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
679 1067
                        'path' => [$entityDir],
680
                        'use_simple_annotation_reader' => false,
681
                    );
682
                }
683
            }
684
        }
685
686
        $options = array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
687 1067
            'mappings' => $ormMappings
688
        );
689
690 1067
        if (!$this['debug']) {
691
            $cacheDrivers = array();
692
            if (array_key_exists('doctrine_cache', $this['config'])) {
693
                $cacheDrivers = $this['config']['doctrine_cache'];
694
            }
695
696
            if (array_key_exists('metadata_cache', $cacheDrivers)) {
697
                $options['metadata_cache'] = $cacheDrivers['metadata_cache'];
698
            }
699
            if (array_key_exists('query_cache', $cacheDrivers)) {
700
                $options['query_cache'] = $cacheDrivers['query_cache'];
701
            }
702
            if (array_key_exists('result_cache', $cacheDrivers)) {
703
                $options['result_cache'] = $cacheDrivers['result_cache'];
704
            }
705
            if (array_key_exists('hydration_cache', $cacheDrivers)) {
706
                $options['hydration_cache'] = $cacheDrivers['hydration_cache'];
707
            }
708
        }
709
710 1067
        $this->register(new \Dflydev\Provider\DoctrineOrm\DoctrineOrmServiceProvider(), array(
711 1067
            'orm.proxies_dir' => __DIR__.'/../../app/cache/doctrine/proxies',
712 1067
            'orm.em.options' => $options,
713
            'orm.custom.functions.string' => array(
714
                'NORMALIZE' => 'Eccube\Doctrine\ORM\Query\Normalize',
715
            ),
716
            'orm.custom.functions.numeric' => array(
717
                'EXTRACT' => 'Eccube\Doctrine\ORM\Query\Extract',
718
            ),
719
        ));
720
721 1067
        $this->extend(
722 1067
            'orm.em.config',
723
            function (\Doctrine\ORM\Configuration $config, \Silex\Application $app) {
724
725
                /** @var $chain \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain */
726 1067
                $chain = $config->getMetadataDriverImpl();
727 1067
                $drivers = $chain->getDrivers();
728 1067
                foreach ($drivers as $namespace => $oldDriver) {
729 1067
                    if ('Eccube\Entity' === $namespace) {
730 1067
                        $newDriver = new AnnotationDriver(
731 1067
                            $app['annotations'],
732 1067
                            $oldDriver->getPaths());
733 1067
                        $newDriver->setFileExtension($oldDriver->getFileExtension());
734 1067
                        $newDriver->addExcludePaths($oldDriver->getExcludePaths());
735 1067
                        $newDriver->setTraitProxiesDirectory(
736 1067
                            realpath(__DIR__.'/../../app/proxy/entity'));
737 1067
                        $chain->addDriver($newDriver, $namespace);
738
                    }
739
                }
740
741 1067
                return $config;
742 1067
            }
743
        );
744
745
        $this->extend('orm.em', function (\Doctrine\ORM\EntityManager $em, \Silex\Application $app) {
746
            // save
747 1067
            $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...
748 1067
            $em->getEventManager()->addEventSubscriber($saveEventSubscriber);
749
750
            // load
751 1067
            $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...
752 1067
            $em->getEventManager()->addEventSubscriber($loadEventSubscriber);
753
754
            // clear cache
755 1067
            $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...
756 1067
            $em->getEventManager()->addEventSubscriber($clearCacheEventSubscriber);
757
758
            // filters
759 1067
            $config = $em->getConfiguration();
760 1067
            $config->addFilter("nostock_hidden", '\Eccube\Doctrine\Filter\NoStockHiddenFilter');
761 1067
            $config->addFilter("incomplete_order_status_hidden", '\Eccube\Doctrine\Filter\OrderStatusFilter');
762
763 1067
            return $em;
764 1067
        });
765
766 1067
        if (!$this['debug']) {
767
            // second level cacheの設定.
768
            $this->extend(
769
                'orm.em.config',
770
                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...
771
                    $config->setSecondLevelCacheEnabled();
772
                    $cacheConfig = $config->getSecondLevelCacheConfiguration();
773
                    $regionConfig = $cacheConfig->getRegionsConfiguration();
774
                    // TODO キャッシュ先は設定で切り替えられるように
775
                    $cache = $this['orm.cache.factory'](
776
                        'filesystem',
777
                        [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
778
                            'path' => __DIR__.'/../../app/cache/doctrine/second'
779
                        ]
780
                    );
781
                    $factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($regionConfig, $cache);
782
                    $cacheConfig->setCacheFactory($factory);
783
784
                    return $config;
785
                }
786
            );
787
        }
788
    }
789
790 1067
    public function initSecurity()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
791
    {
792 1067
        $this->register(new \Silex\Provider\SecurityServiceProvider());
793 1067
        $this->register(new \Silex\Provider\CsrfServiceProvider());
794 1067
        $this->register(new \Silex\Provider\RememberMeServiceProvider());
795
796 1067
        $this['security.firewalls'] = array(
797 1067
            'admin' => array(
798 1067
                'pattern' => "^/{$this['config']['admin_route']}/",
799
                'form' => array(
800 1067
                    'login_path' => "/{$this['config']['admin_route']}/login",
801 1067
                    'check_path' => "/{$this['config']['admin_route']}/login_check",
802 1067
                    'username_parameter' => 'login_id',
803 1067
                    'password_parameter' => 'password',
804
                    'with_csrf' => true,
805
                    'use_forward' => true,
806
                ),
807
                'logout' => array(
808 1067
                    'logout_path' => "/{$this['config']['admin_route']}/logout",
809 1067
                    'target_url' => "/{$this['config']['admin_route']}/",
810
                ),
811 1067
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Member'),
812
                'anonymous' => true,
813
            ),
814
            'customer' => array(
815 1067
                'pattern' => '^/',
816
                'form' => array(
817
                    'login_path' => '/mypage/login',
818
                    'check_path' => '/login_check',
819
                    'username_parameter' => 'login_email',
820
                    'password_parameter' => 'login_pass',
821
                    'with_csrf' => true,
822
                    'use_forward' => true,
823
                ),
824
                'logout' => array(
825
                    'logout_path' => '/logout',
826
                    'target_url' => '/',
827
                ),
828
                'remember_me' => array(
829 1067
                    'key' => sha1($this['config']['auth_magic']),
830 1067
                    'name' => $this['config']['cookie_name'].'_rememberme',
831
                    // lifetimeはデフォルトの1年間にする
832
                    // 'lifetime' => $this['config']['cookie_lifetime'],
833 1067
                    'path' => $this['config']['root_urlpath'] ?: '/',
834 1067
                    'secure' => $this['config']['force_ssl'],
835
                    'httponly' => true,
836
                    'always_remember_me' => false,
837 1067
                    'remember_me_parameter' => 'login_memory',
838
                ),
839 1067
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Customer'),
840
                'anonymous' => true,
841
            ),
842
        );
843
844 1067
        $channel = null;
845
        // 強制SSL
846 1067
        if ($this['config']['force_ssl'] == \Eccube\Common\Constant::ENABLED) {
847
            $channel = "https";
848
        }
849
850 1067
        $this['security.access_rules'] = array(
851 1067
            array("^/{$this['config']['admin_route']}/login", 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
852 1067
            array("^/{$this['config']['admin_route']}/", 'ROLE_ADMIN', $channel),
853 1067
            array('^/mypage/login', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
854 1067
            array('^/mypage/withdraw_complete', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
855 1067
            array('^/mypage/change', 'IS_AUTHENTICATED_FULLY', $channel),
856 1067
            array('^/mypage', 'ROLE_USER', $channel),
857
        );
858
859
        $this['eccube.password_encoder'] = function ($app) {
860 1065
            return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
861
        };
862
        $this['security.encoder_factory'] = function ($app) {
863 1065
            return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
864 1065
                'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
865 1065
                'Eccube\Entity\Member' => $app['eccube.password_encoder'],
866
            ));
867
        };
868
        $this['eccube.event_listner.security'] = function ($app) {
869 1067
            return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
870
        };
871
872
        // Voterの設定
873
        $this['authority_voter'] = function ($app) {
874 1065
            return new \Eccube\Security\Voter\AuthorityVoter($app);
875
        };
876
877
        $this->extend('security.voters', function ($voters, \Silex\Application $app) {
878 1065
            $voters[] = $app['authority_voter'];
879
880 1065
            return $voters;
881 1067
        });
882
883
        $this['security.access_manager'] = function ($app) {
884 1065
            return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
885
        };
886
887 1067
        $this->on(\Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN, array($this['eccube.event_listner.security'], 'onInteractiveLogin'));
888
    }
889
890
    /**
891
     * ロードバランサー、プロキシサーバの設定を行う
892
     */
893 1067
    public function initProxy()
894
    {
895 1067
        $config = $this['config'];
896 1067
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
897
            $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($config) {
898
                // サブリクエストのREMOTE_ADDRも動的に設定を行う必要があるため、KernelEvents::REQUESTを使用する
899
                Request::setTrustedProxies(array_merge(array($event->getRequest()->server->get('REMOTE_ADDR')), $config['trusted_proxies']));
900
            }, self::EARLY_EVENT);
901 1067 View Code Duplication
        } elseif (isset($config['trusted_proxies']) && !empty($config['trusted_proxies'])) {
902
            Request::setTrustedProxies($config['trusted_proxies']);
903
        }
904
    }
905
906 1065
    public function initializePlugin()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
907
    {
908 1065
        if ($this->initializedPlugin) {
909
            return;
910
        }
911 1065
        $this->register(new ServiceProvider\EccubePluginServiceProvider());
912
913
        // TODO Acme\ServiceProvider の初期化はここで OK?
914 1065
        if (array_key_exists('service',$this['config'])) {
0 ignored issues
show
introduced by
Add a single space after each comma delimiter
Loading history...
915
            foreach ($this['config']['service'] as $service) {
916
                $this->register(new $service);
0 ignored issues
show
introduced by
Use parentheses when instantiating classes
Loading history...
917
            }
918
        }
919 1065
        $this->initializedPlugin = true;
920
    }
921
922
    /**
923
     * PHPUnit を実行中かどうかを設定する.
924
     *
925
     * @param boolean $testMode PHPUnit を実行中の場合 true
926
     */
927 1057
    public function setTestMode($testMode)
928
    {
929 1057
        $this->testMode = $testMode;
930
    }
931
932
    /**
933
     * PHPUnit を実行中かどうか.
934
     *
935
     * @return boolean PHPUnit を実行中の場合 true
936
     */
937 319
    public function isTestMode()
938
    {
939 319
        return $this->testMode;
940
    }
941
942
    /**
943
     *
944
     * データベースの接続を確認
945
     * 成功 : trueを返却
946
     * 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
947
     * 備考 : app['debug']がtrueの際は処理を行わない
948
     *
949
     * @return boolean true
950
     *
951
     */
952 1067
    protected function checkDatabaseConnection()
953
    {
954 1067
        if ($this['debug']) {
955 1067
            return;
956
        }
957
        try {
958
            $this['db']->connect();
959
        } catch (\Doctrine\DBAL\DBALException $e) {
960
            $this['monolog']->error($e->getMessage());
961
            $this['twig.path'] = array(__DIR__.'/Resource/template/exception');
962
            $html = $this['twig']->render('error.twig', array(
963
                'error_title' => 'データーベース接続エラー',
964
                'error_message' => 'データーベースを確認してください',
965
            ));
966
            $response = new Response();
967
            $response->setContent($html);
968
            $response->setStatusCode('500');
969
            $response->headers->set('Content-Type', 'text/html');
970
            $response->send();
971
            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...
972
        }
973
974
        return true;
975
    }
976
977
    /**
978
     * Config ファイルをパースし、連想配列を返します.
979
     *
980
     * $config_name.yml ファイルをパースし、連想配列を返します.
981
     * $config_name.php が存在する場合は、 PHP ファイルに記述された連想配列を使用します。
982
     *
983
     * @param string $config_name Config 名称
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
984
     * @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...
985
     * @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...
986
     * @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...
987
     * @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...
988
     * @return Application
989
     */
990 1068
    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...
991
    {
992 1068
        $ymlPath = $ymlPath ? $ymlPath : __DIR__.'/../../app/config/eccube';
993 1068
        $distPath = $distPath ? $distPath : __DIR__.'/../../src/Eccube/Resource/config';
994
995 1068
        $config = [];
996 1068
        $config_php = $ymlPath.'/'.$config_name.'.php';
997 1068
        if (file_exists($config_php)) {
998 1068
            $config = require $config_php;
999
        }
1000
1001
        // `%ROOT_DIR%`を絶対パスに変換
1002 1068
        $rootDir = realpath(__DIR__.'/../../');
1003
        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...
1004 1068
            $value = str_replace('%ROOT_DIR%', $rootDir, $value);
1005 1068
        });
1006
1007 1068
        $config_php_dist = $distPath.'/'.$config_name.'.php';
1008 1068
        $config_dist = require $config_php_dist;
1009
1010
        // `%ROOT_DIR%`を絶対パスに変換
1011
        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...
1012 1068
            $value = str_replace('%ROOT_DIR%', $rootDir, $value);
1013 1068
        });
1014
1015 1068
        if ($wrap_key) {
1016 1068
            $configAll = array_replace_recursive($configAll, array($config_name => $config_dist), array($config_name => $config));
1017
        } else {
1018 1068
            $configAll = array_replace_recursive($configAll, $config_dist, $config);
1019
        }
1020
1021 1068
        return $this;
1022
    }
1023
1024
    /**
1025
     * セッションが開始されているかどうか.
1026
     *
1027
     * @return boolean セッションが開始済みの場合 true
1028
     * @link http://php.net/manual/ja/function.session-status.php#113468
1029
     */
1030 1067
    protected function isSessionStarted()
1031
    {
1032 1067
        if (php_sapi_name() !== 'cli') {
1033 1067
            if (version_compare(phpversion(), '5.4.0', '>=')) {
1034 1067
                return session_status() === PHP_SESSION_ACTIVE ? true : false;
1035
            } else {
1036
                return session_id() === '' ? false : true;
1037
            }
1038
        }
1039
1040
        return false;
1041
    }
1042
1043
    /**
1044
     * Http Cache対応
1045
     */
1046 1067
    protected function initCacheRequest()
1047
    {
1048
        // httpキャッシュが無効の場合はイベント設定を行わない.
1049 1067
        if (!$this['config']['http_cache']['enabled']) {
1050 1067
            return;
1051
        }
1052
1053
        $app = $this;
1054
1055
        // Response Event(http cache対応、event実行は一番遅く設定)
1056
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
1057
1058
            if (!$event->isMasterRequest()) {
1059
                return;
1060
            }
1061
1062
            $request = $event->getRequest();
1063
            $response = $event->getResponse();
1064
1065
            $route = $request->attributes->get('_route');
1066
1067
            $etag = md5($response->getContent());
1068
1069
            if (strpos($route, 'admin') === 0) {
1070
                // 管理画面
1071
1072
                // 管理画面ではコンテンツの中身が変更された時点でキャッシュを更新し、キャッシュの適用範囲はprivateに設定
1073
                $response->setCache(array(
1074
                    'etag' => $etag,
1075
                    'private' => true,
1076
                ));
1077
1078
                if ($response->isNotModified($request)) {
1079
                    return $response;
1080
                }
1081
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1082
            } else {
1083
                // フロント画面
1084
                $cacheRoute = $app['config']['http_cache']['route'];
1085
1086
                if (in_array($route, $cacheRoute) === true) {
1087
                    // キャッシュ対象となる画面lが含まれていた場合、キャッシュ化
1088
                    // max-ageを設定しているためExpiresは不要
1089
                    // Last-Modifiedだと比較する項目がないためETagで対応
1090
                    // max-ageを設定していた場合、contentの中身が変更されても変更されない
1091
1092
                    $age = $app['config']['http_cache']['age'];
1093
1094
                    $response->setCache(array(
1095
                        'etag' => $etag,
1096
                        'max_age' => $age,
1097
                        's_maxage' => $age,
1098
                        'public' => true,
1099
                    ));
1100
1101
                    if ($response->isNotModified($request)) {
1102
                        return $response;
1103
                    }
1104
                }
1105
            }
1106
1107
        }, -1024);
1108
    }
1109
}
1110