Failed Conditions
Pull Request — experimental/3.1 (#2525)
by Kiyotaka
54:52 queued 29:13
created

Application::initialize()   C

Complexity

Conditions 12
Paths 3

Size

Total Lines 219
Code Lines 141

Duplication

Lines 22
Ratio 10.05 %

Code Coverage

Tests 112
CRAP Score 12.439

Importance

Changes 0
Metric Value
cc 12
eloc 141
nc 3
nop 0
dl 22
loc 219
ccs 112
cts 131
cp 0.855
crap 12.439
rs 5.034
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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