Completed
Pull Request — experimental/3.1 (#2515)
by Kentaro
147:20 queued 92:31
created

Application   F

Complexity

Total Complexity 107

Size/Duplication

Total Lines 1027
Duplicated Lines 2.73 %

Coupling/Cohesion

Components 2
Dependencies 90

Test Coverage

Coverage 77.25%

Importance

Changes 0
Metric Value
dl 28
loc 1027
ccs 384
cts 497
cp 0.7725
rs 0.9026
c 0
b 0
f 0
wmc 107
lcom 2
cbo 90

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
B isSessionStarted() 0 12 5
B initCacheRequest() 0 63 7
B initConfig() 0 25 2
A initLogger() 0 5 1
D initialize() 22 219 13
B initLocale() 0 29 5
B initSession() 0 24 3
D initRendering() 0 139 20
C initMailer() 0 29 8
F initDoctrine() 3 172 14
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 28 5

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