Failed Conditions
Pull Request — experimental/3.1 (#2534)
by chihiro
42:21
created

Application::initClassLoader()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

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

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

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

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

Loading history...
151 1067
    }
152 2
153
    public function initClassLoader()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
154
    {
155
        if (!isset($this['config']['vendor_name'])) {
156 1067
            $this['logger']->log('config.vendor_name is not set.');
157
158
            return;
159 1067
        }
160 1067
161
        $name = $this['config']['vendor_name'];
162
        $dir = $this['config']['root_dir'].'/app/'.$name;
163
164 1067
        if (false === file_exists($dir)) {
165
            $this['logger']->log(sprintf('%s is not exists.', $dir));
166
167 1067
            return;
168 1067
        }
169
170 1067
        $path = realpath($dir);
171 1067
172 1067
        $loader = $this['eccube.autoloader'];
173 1067
        $loader->addPsr4($name.'\\', $path);
174 1067
175 1067
        $config = $this['config'];
176 1067
        $config['vendor_dir'] = $path;
177
        $this->overwrite('config', $config);
178
    }
179 25
180 25
    public function initialize()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
181
    {
182
        if ($this->initialized) {
183
            return;
184
        }
185
186
        // init locale
187
        $this->initLocale();
188
189
        // init session
190
        if (!$this->isSessionStarted()) {
191
            $this->initSession();
192
        }
193
194
        // init twig
195
        $this->initRendering();
196
197
        // init provider
198
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
199
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
200
        ));
201
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
202 1067
        $this->register(new \Silex\Provider\FormServiceProvider());
203
        $this->register(new \Silex\Provider\SerializerServiceProvider());
204
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
205 1067
        $this->register(new \Saxulum\Validator\Provider\SaxulumValidatorProvider());
206
        $this->register(new MobileDetectServiceProvider());
207 1067
        $this->register(new TwigLintServiceProvider());
208 1067
209 1067
        $this->error(function (\Exception $e, Request $request, $code) {
210
            if ($this['debug']) {
211 1067
                return;
212 1067
            }
213
214
            switch ($code) {
215
                case 403:
216
                    $title = 'アクセスできません。';
217 1067
                    $message = 'お探しのページはアクセスができない状況にあるか、移動もしくは削除された可能性があります。';
218
                    break;
219
                case 404:
220 1067
                    $title = 'ページがみつかりません。';
221
                    $message = 'URLに間違いがないかご確認ください。';
222
                    break;
223 1067
                default:
224
                    $title = 'システムエラーが発生しました。';
225 1067
                    $message = '大変お手数ですが、サイト管理者までご連絡ください。';
226 1067
                    break;
227
            }
228 1067
229 1067
            return $this->render('error.twig', array(
230 1067
                'error_title' => $title,
231
                'error_message' => $message,
232
            ));
233
        });
234
235 1067
        // init mailer
236
        $this->initMailer();
237 1067
238 1067
        $this->register(new \Sergiors\Silex\Provider\DoctrineCacheServiceProvider());
239
        $this->register(new \Sergiors\Silex\Provider\AnnotationsServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
240
            'annotations.debug' => $this['debug'],
241 1067
            'annotations.options' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
242
                'cache_driver' => $this['debug'] ? 'array' : 'filesystem',
243
                'cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/annotation'
244
            ]
245
        ]);
246 1067
247 1067
        // init doctrine orm
248
        $this->initDoctrine();
249
250 1067
        // Set up the DBAL connection now to check for a proper connection to the database.
251
        $this->checkDatabaseConnection();
252 1067
253 1067
        // init security
254 1067
        $this->initSecurity();
255 1067
256 1067
        $this->register(new \Sergiors\Silex\Provider\RoutingServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
257 1067
            'routing.cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/routing'
258 1067
        ]);
259 1067
        $this->register(new \Sergiors\Silex\Provider\TemplatingServiceProvider());
260 1067
        $this->register(new \Sergiors\Silex\Provider\SensioFrameworkExtraServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
261 1067
            'request' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
262 1067
                'auto_convert' => true
263 1067
            ]
264 1067
        ]);
265 1067
        // init proxy
266 1067
        $this->initProxy();
267 1067
268 1067
        $enabledPlugins = $this['orm.em']->getRepository('Eccube\Entity\Plugin')->findAllEnabled();
269 1067
        $configRootDir = $this['config']['root_dir'];
270 1067
        $enabledPluginDirs = array_map(function($plugin) use ($configRootDir) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
271 1067
            return $configRootDir.'/app/Plugin/'.$plugin->getCode();
272 1067
        }, $enabledPlugins);
273 1067
274
        $pluginSubDirs = (function($dirName) use ($enabledPluginDirs) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
275 1067
            return array_map(function($pluginDir) use ($dirName) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
276
                return $pluginDir . '/' . $dirName;
0 ignored issues
show
Coding Style introduced by
Concat operator must not be surrounded by spaces
Loading history...
277
            }, $enabledPluginDirs);
278 1067
        });
279 1067
280 1067
        // init ec-cube service provider
281
        $this->register(new DiServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
282 1067
            'eccube.di.scanners' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
283 1067
                new ComponentScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
284
                    $this['config']['vendor_dir'].'/Controller',
285
                    $this['config']['root_dir'].'/src/Eccube/Controller'
286
                ], $pluginSubDirs('Controller'))),
287 1067
                new FormTypeScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
288
                    $this['config']['root_dir'].'/src/Eccube/Form/Type'
289
                ], $pluginSubDirs('Form/Type'))),
290 1067
                new FormExtensionScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
291 1067
                    $this['config']['root_dir'].'/src/Eccube/Form/Extension'
292 1067
                ], $pluginSubDirs('Form/Extension'))),
293 1067
                new ServiceScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
294 1067
                    $this['config']['root_dir'].'/src/Eccube/Service'
295 1067
                ], $pluginSubDirs('Service'))),
296
                new RepositoryScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
297 1067
                    $this['config']['root_dir'].'/src/Eccube/Repository'
298 1067
                ], $pluginSubDirs('Repository'))),
299 1067
                new QueryExtensionScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
300 1067
                    $this['config']['root_dir'].'/src/Eccube/Repository'
301 1067
                ], $pluginSubDirs('Repository'))),
302 1067
                new EntityEventScanner(array_merge([
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
303
                    $this['config']['vendor_dir'].'/Entity'
304
                ], $pluginSubDirs('Entity')))
305 1067
            ],
306 1067
            'eccube.di.generator.dir' => $this['config']['root_dir'].'/app/cache/provider'
307 1067
        ]);
308
309 1067
        $this->register(new CompatRepositoryProvider());
310 1067
        $this->register(new CompatServiceProvider());
311
        $this->register(new ServiceProvider\EccubeServiceProvider());
312
313 1067
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
314 1067
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
315
316 1067
        // ルーティングの設定
317
        // TODO EccubeRoutingServiceProviderに移植する.
318
        $app = $this;
319 1067
        $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...
320
            $options = [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
321
                'debug' => $app['debug'],
322
                'cache_dir' => $app['routing.cache_dir'],
323 1067
                'matcher_base_class' => $app['request_matcher_class'],
324 1067
                'matcher_class' => $app['request_matcher_class'],
325
                'matcher_cache_class' => $cachePrefix.'UrlMatcher',
326 1067
                'generator_cache_class' => $cachePrefix.'UrlGenerator'
327
            ];
328 1067
            $router = new EccubeRouter(
329
                $app['routing.loader'],
330
                $resoure,
331
                $options,
332 1067
                $app['request_context'],
333 1067
                $app['logger']
334 1067
            );
335
336
            $router->setAdminPrefix($app['config']['admin_route']);
337 1067
            $router->setUserDataPrefix($app['config']['user_data_route']);
338 1067
            $router->setRequireHttps($app['config']['force_ssl']);
339
340 1067
            return $router;
341 1067
        });
342
343
        $this['eccube.router.origin'] = function ($app) {
344 1067
            $resource = __DIR__.'/Controller';
345 1067
            $cachePrefix = 'Origin';
346 1067
347
            return $app['eccube.router']($resource, $cachePrefix);
348
        };
349 1067
350 1067
        $this['eccube.routers.plugin'] = [];
351
352 1067
        if (isset($this['config']['vendor_dir'])) {
353 1067
            $this['eccube.router.extend'] = function ($app) {
354
                $resource = $app['config']['vendor_dir'].'/Controller';
355
                $cachePrefix = 'Extend';
356
357 1067
                $router = $app['eccube.router']($resource, $cachePrefix);
358 1067
359
                return $router;
360
            };
361 1067
        }
362
        $this->extend('request_matcher', function ($matcher, $app) {
363 1067
            $matchers = [];
364 1067
            if (isset($app['config']['vendor_dir'])) {
365
                $matchers[] = $app['eccube.router.extend'];
366
            }
367 1067
            foreach ($app['eccube.routers.plugin'] as $router) {
368
                $matchers[] = $router;
369 1067
            };
370
            $matchers[] = $app['eccube.router.origin'];
371
            $matchers[] = $matcher;
372 1067
373
            return new ChainUrlMatcher($matchers, $app['request_context']);
374
        });
375 1067
376 1067
        $this->extend('url_generator', function ($generator, $app) {
377
            $generators = [];
378
            $generators[] = $app['eccube.router.extend'];
379
            foreach ($app['eccube.routers.plugin'] as $router) {
380 1067
                $generators[] = $router;
381 1067
            };
382
            $generators[] = $app['eccube.router.origin'];
383
            $generators[] = $generator;
384 1067
385 1067
            return new ChainUrlGenerator($generators, $app['request_context']);
386 1067
        });
387
388
        // Route CollectionにEC-CUBEで定義したルーティングを追加(debug tool barに出力するため)
389
        $this->extend('routes', function ($routes, $app) {
390 1067
            $routes->addCollection($app['eccube.router.extend']->getRouteCollection());
391
            foreach ($app['eccube.routers.plugin'] as $router) {
392 1067
                $routes->addCollection($router->getRouteCollection());
393 1067
            };
394 1067
            $routes->addCollection($app['eccube.router.origin']->getRouteCollection());
395 1067
396
            return $routes;
397
        });
398 1067
399 1067
        // init http cache
400
        $this->initCacheRequest();
401
402 1067
        $this->initialized = true;
403
    }
404 1067
405 1067
    public function initLocale()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
406
    {
407 1067
        // locale
408 1067
        if (!empty($this['config']['locale'])) {
409 1067
            \Locale::setDefault($this['config']['locale']);
410 1067
        };
411
412
        // timezone
413
        if (!empty($this['config']['timezone'])) {
414
            date_default_timezone_set($this['config']['timezone']);
415
        }
416
417 1067
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
418
            'locale' => $this['config']['locale'],
419 1067
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
420
            'locale_fallbacks' => ['ja', 'en'],
421
        ));
422
        $this->extend('translator', function ($translator, \Silex\Application $app) {
423
            $translator->addLoader('php', new \Symfony\Component\Translation\Loader\PhpFileLoader());
424
425
            $file = __DIR__.'/Resource/locale/messages.'.$app['locale'].'.php';
426
            if (file_exists($file)) {
427 1067
                $translator->addResource('php', $file, $app['locale']);
428
                $translator->addResource('php', $file, $app['locale'], 'validators');
429 1067
            }
430 1067
431
            return $translator;
432
        });
433 1067
    }
434 1067
435
    public function initSession()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
436 1067
    {
437 1067
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
438
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
439
            'session.storage.options' => array(
440 319
                'name' => $this['config']['cookie_name'],
441 319
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
442 319
                'cookie_secure' => $this['config']['force_ssl'],
443 221
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
444
                'cookie_httponly' => true,
445 98
                // cookie_domainは指定しない
446
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
447
            ),
448
        ));
449 319
450 221
        $options = $this['config']['session_handler'];
451 221
452
        if ($options['enabled']) {
453 221
            // @see http://silex.sensiolabs.org/doc/providers/session.html#custom-session-configurations
454 221
            $this['session.storage.handler'] = null;
455 221
            ini_set('session.save_handler', $options['save_handler']);
456
            ini_set('session.save_path', $options['save_path']);
457
        }
458 98
    }
459
460
    public function initRendering()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
461
    {
462
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
463
            'twig.form.templates' => array('Form/form_layout.twig'),
464
        ));
465 98
        $this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
466 98
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
467
            $twig->addExtension(new \Twig_Extension_StringLoader());
468 98
469 98
            return $twig;
470 98
        });
471
472 319
        $this->before(function (Request $request, \Silex\Application $app) {
473 319
            $app['admin'] = $app['front'] = false;
474
            $pathinfo = rawurldecode($request->getPathInfo());
475
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
476 319
                $app['admin'] = true;
477
            } else {
478 221
                $app['front'] = true;
479 221
            }
480
481
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
482
            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...
483
                if (file_exists(__DIR__.'/../../app/template/admin')) {
484
                    $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...
485 1067
                }
486
                $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...
487
                $paths[] = __DIR__.'/../../app/Plugin';
488
                $cacheDir =  __DIR__.'/../../app/cache/twig/admin';
489
            } else {
490
                // モバイル端末時、smartphoneディレクトリを探索パスに追加する.
491 317
                if ($app['mobile_detect.device_type'] == \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_SP) {
492 71
                    if (file_exists(__DIR__.'/../../app/template/smartphone')) {
493
                        $paths[] = __DIR__.'/../../app/template/smartphone';
494
                    }
495 317
                    $paths[] = __DIR__.'/Resource/template/smartphone';
496
                }
497 317
498
                if (file_exists($app['config']['template_realdir'])) {
499
                    $paths[] = $app['config']['template_realdir'];
500 221
                }
501 221
                $paths[] = $app['config']['template_default_realdir'];
502
                $paths[] = __DIR__.'/../../app/Plugin';
503 221
                $cacheDir =  __DIR__.'/../../app/cache/twig/'.$app['config']['template_code'];
504 221
            }
505
            $app['twig']->setCache($app['debug'] ? null : $cacheDir);
506 218
            $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
507
508 218
            // 管理画面のIP制限チェック.
509 218
            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...
510 218
                // IP制限チェック
511
                $allowHost = $app['config']['admin_allow_hosts'];
512 3
                if (count($allowHost) > 0) {
513
                    if (array_search($app['request_stack']->getCurrentRequest()->getClientIp(), $allowHost) === false) {
514
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
515 221
                    }
516
                }
517
            }
518
        }, self::EARLY_EVENT);
519
520 96
        // twigのグローバル変数を定義.
521 96
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) {
522
            // 未ログイン時にマイページや管理画面以下にアクセスするとSubRequestで実行されるため,
523
            // $event->isMasterRequest()ではなく、グローバル変数が初期化済かどうかの判定を行う
524 96
            if (isset($this['twig_global_initialized']) && $this['twig_global_initialized'] === true) {
525 2
                return;
526 2
            }
527
            // ショップ基本情報
528 94
            $this['twig']->addGlobal('BaseInfo', $this[BaseInfo::class]);
529
530
            if ($this->isAdminRequest()) {
531
                // 管理画面
532
                // 管理画面メニュー
533 96
                $menus = array('', '', '');
534
                $this['twig']->addGlobal('menus', $menus);
535
536 96
                $Member = $this->user();
537
                if (is_object($Member)) {
538
                    // ログインしていれば管理者のロールを取得
539
                    $AuthorityRoles = $this['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
540 96
541 96
                    $roles = array();
542 96
                    $request = $event->getRequest();
543 96
                    foreach ($AuthorityRoles as $AuthorityRole) {
544 96
                        // 管理画面でメニュー制御するため相対パス全てをセット
545 96
                        $roles[] = $request->getBaseUrl().'/'.$this['config']['admin_route'].$AuthorityRole->getDenyUrl();
546 96
                    }
547 96
548 96
                    $this['twig']->addGlobal('AuthorityRoles', $roles);
549 96
                }
550 96
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
551 96
            } else {
552 96
                // フロント画面
553 96
                $request = $event->getRequest();
554 96
                $route = $request->attributes->get('_route');
555 34
556 34
                // ユーザ作成画面
557
                if ($route === 'user_data') {
558
                    $params = $request->attributes->get('_route_params');
559 96
                    $route = $params['route'];
560 96
                    // プレビュー画面
561
                } elseif ($request->get('preview')) {
562
                    $route = 'preview';
563 317
                }
564 1067
565
                try {
566
                    $device_type_id = $this['mobile_detect.device_type'];
567 1067
568
                    // TODO デバッグ用
569
                    if ($request->query->has('device_type_id')) {
570
                        $device_type_id = $request->get('device_type_id', \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
571 1067
                    }
572
573
                    $DeviceType = $this['eccube.repository.master.device_type']
574
                        ->find($device_type_id);
575
                    $qb = $this['eccube.repository.page']->createQueryBuilder('p');
576
                    $Page = $qb->select('p, pll,l, bp, b')
577
                        ->leftJoin('p.PageLayouts', 'pll')
578
                        ->leftJoin('pll.Layout', 'l')
579
                        ->leftJoin('l.BlockPositions', 'bp')
580
                        ->leftJoin('bp.Block', 'b')
581
                        ->where('p.url = :route')
582 1067
                        ->andWhere('l.DeviceType = :DeviceType')
583 1067
                        ->orderBy('bp.block_row', 'ASC')
584
                        ->setParameter('route', $route)
585 1067
                        ->setParameter('DeviceType', $DeviceType)
586
                        ->getQuery()
587
                        ->getSingleResult();
588
                } catch (\Doctrine\ORM\NoResultException $e) {
589 1067
                    $Page = $this['eccube.repository.page']->newPage($DeviceType);
0 ignored issues
show
Bug introduced by
The variable $DeviceType does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
590 1067
                }
591
592 1067
                $this['twig']->addGlobal('Page', $Page);
593
                $this['twig']->addGlobal('title', $Page->getName());
594
            }
595
596
            $this['twig_global_initialized'] = true;
597 1067
        });
598
    }
599 1067
600 1067
    public function initMailer()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
601
    {
602 1067
603
        // メール送信時の文字エンコード指定(デフォルトはUTF-8)
604
        if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
605 1067
            if ($this['config']['mail']['charset_iso_2022_jp'] === true) {
606
                \Swift::init(function () {
607 1067
                    \Swift_DependencyContainer::getInstance()
608
                        ->register('mime.qpheaderencoder')
609 1067
                        ->asAliasOf('mime.base64headerencoder');
610 1067
                    \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
611
                });
612 1067
            }
613 1067
        }
614
615
        $this->register(new \Silex\Provider\SwiftmailerServiceProvider());
616
        $this['swiftmailer.options'] = $this['config']['mail'];
617 1067
618 1067
        if (isset($this['config']['mail']['spool']) && is_bool($this['config']['mail']['spool'])) {
619 1067
            $this['swiftmailer.use_spool'] = $this['config']['mail']['spool'];
620 1067
        }
621
        // デフォルトはsmtpを使用
622
        $transport = $this['config']['mail']['transport'];
623 1067
        if ($transport == 'sendmail') {
624 1067
            $this['swiftmailer.transport'] = \Swift_SendmailTransport::newInstance();
625 1067
        } elseif ($transport == 'mail') {
626
            $this['swiftmailer.transport'] = \Swift_MailTransport::newInstance();
627
        }
628
    }
629
630
    public function initDoctrine()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
631
    {
632
        $this->register(new EntityEventServiceProvider());
633
        $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...
634
            'dbs.options' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
635 1067
                'default' => $this['config']['database'][$this['config']['database']['default']]
636
            )
637
        ));
638
        $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Provider\DoctrineOrmManagerRegistryProvider());
639
640
        $app = $this;
641
        $this->extend('db.event_manager', function ($evm) use ($app) {
642
            $initSubscriber = new InitSubscriber($app);
643
            $evm->addEventSubscriber($initSubscriber);
644 1067
645 1067
            return $evm;
646
        });
647 1067
648
        // UTCで保存
649
        // @see http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/cookbook/working-with-datetime.html
650
        UTCDateTimeType::setTimeZone($this['config']['timezone']);
651
        UTCDateTimeTzType::setTimeZone($this['config']['timezone']);
652
        Type::overrideType('datetime', UTCDateTimeType::class);
653
        Type::overrideType('datetimetz', UTCDateTimeTzType::class);
654
655
        // プラグインのmetadata定義を合わせて行う.
656
        $pluginConfigs = PluginConfigManager::getPluginConfigAll($this['debug']);
657
        $ormMappings = array();
658
        $ormMappings[] = array(
659
             'type' => 'annotation',
660
             'namespace' => 'Eccube\Entity',
661
             'path' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
662
                 __DIR__.'/Entity'
663
             ),
664
             'use_simple_annotation_reader' => false,
665
         );
666 1067
667 1067
        if (isset($this['config']['vendor_dir'])) {
668
            $ormMappings[] = array(
669
                'type' => 'annotation',
670
                'namespace' => $this['config']['vendor_name'].'\Entity',
671
                'path' => array(
672
                    $this['config']['vendor_dir'].'/Entity',
673
                ),
674 1067
                'use_simple_annotation_reader' => false,
675 1067
            );
676 1067
        }
677 1067
678 1067
        foreach ($pluginConfigs as $code) {
679 1067
            $config = $code['config'];
680
            // Doctrine Extend
681
            if (isset($config['orm.path']) && is_array($config['orm.path'])) {
682
                // orm.pathが明示されている場合
683
                $paths = array();
684
                foreach ($config['orm.path'] as $path) {
685
                    $paths[] = $this['config']['plugin_realdir'].'/'.$config['code'].$path;
686
                }
687 1067
                $ormMappings[] = array(
688
                    'type' => 'yml',
689
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
690 1067
                    'path' => $paths,
691
                );
692
                $ormMappings[] = array(
693
                    'type' => 'annotation',
694
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
695
                    'path' => $paths,
696
                    'use_simple_annotation_reader' => false,
697
                );
698
            } else {
699
                // orm.pathを省略しても `/Resource/doctrine` と `/Entity` ディレクトリがある場合は設定を追加する
700
                $doctrineDir = $this['config']['plugin_realdir'].'/'.$config['code'].'/Resource/doctrine';
701
                if (glob($doctrineDir.'/*.yml')) {
702
                    $ormMappings[] = array(
703
                        'type' => 'yml',
704
                        'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
705
                        'path' => [$doctrineDir],
706
                    );
707
                }
708
                $entityDir = $this['config']['plugin_realdir'].'/'.$config['code'].'/Entity';
709
                if (file_exists($entityDir)) {
710 1067
                    $ormMappings[] = array(
711 1067
                        'type' => 'annotation',
712 1067
                        'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
713
                        'path' => [$entityDir],
714
                        'use_simple_annotation_reader' => false,
715
                    );
716
                }
717
            }
718
        }
719
720
        $options = array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
721 1067
            'mappings' => $ormMappings
722 1067
        );
723
724
        if (!$this['debug']) {
725
            $cacheDrivers = array();
726 1067
            if (array_key_exists('doctrine_cache', $this['config'])) {
727 1067
                $cacheDrivers = $this['config']['doctrine_cache'];
728 1067
            }
729 1067
730 1067
            if (array_key_exists('metadata_cache', $cacheDrivers)) {
731 1067
                $options['metadata_cache'] = $cacheDrivers['metadata_cache'];
732 1067
            }
733 1067
            if (array_key_exists('query_cache', $cacheDrivers)) {
734 1067
                $options['query_cache'] = $cacheDrivers['query_cache'];
735 1067
            }
736 1067
            if (array_key_exists('result_cache', $cacheDrivers)) {
737 1067
                $options['result_cache'] = $cacheDrivers['result_cache'];
738
            }
739
            if (array_key_exists('hydration_cache', $cacheDrivers)) {
740
                $options['hydration_cache'] = $cacheDrivers['hydration_cache'];
741 1067
            }
742 1067
        }
743
744
        $this->register(new \Dflydev\Provider\DoctrineOrm\DoctrineOrmServiceProvider(), array(
745
            'orm.proxies_dir' => __DIR__.'/../../app/cache/doctrine/proxies',
746
            'orm.em.options' => $options,
747 1067
            'orm.custom.functions.string' => array(
748 1067
                'NORMALIZE' => 'Eccube\Doctrine\ORM\Query\Normalize',
749
            ),
750
            'orm.custom.functions.numeric' => array(
751 1067
                'EXTRACT' => 'Eccube\Doctrine\ORM\Query\Extract',
752 1067
            ),
753
        ));
754
755 1067
        $this->extend(
756 1067
            'orm.em.config',
757
            function (\Doctrine\ORM\Configuration $config, \Silex\Application $app) {
758
759 1067
                /** @var $chain \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain */
760 1067
                $chain = $config->getMetadataDriverImpl();
761 1067
                $drivers = $chain->getDrivers();
762
                foreach ($drivers as $namespace => $oldDriver) {
763 1067
                    if ('Eccube\Entity' === $namespace) {
764 1067
                        $newDriver = new AnnotationDriver(
765
                            $app['annotations'],
766 1067
                            $oldDriver->getPaths());
767
                        $newDriver->setFileExtension($oldDriver->getFileExtension());
768
                        $newDriver->addExcludePaths($oldDriver->getExcludePaths());
769
                        $newDriver->setTraitProxiesDirectory(
770
                            realpath(__DIR__.'/../../app/proxy/entity'));
771
                        $chain->addDriver($newDriver, $namespace);
772
                    }
773
                }
774
775
                return $config;
776
            }
777
        );
778
779
        $this->extend('orm.em', function (\Doctrine\ORM\EntityManager $em, \Silex\Application $app) {
780
            // save
781
            $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...
782
            $em->getEventManager()->addEventSubscriber($saveEventSubscriber);
783
784
            // load
785
            $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...
786
            $em->getEventManager()->addEventSubscriber($loadEventSubscriber);
787
788
            // clear cache
789
            $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...
790 1067
            $em->getEventManager()->addEventSubscriber($clearCacheEventSubscriber);
791
792 1067
            // filters
793 1067
            $config = $em->getConfiguration();
794 1067
            $config->addFilter("nostock_hidden", '\Eccube\Doctrine\Filter\NoStockHiddenFilter');
795
            $config->addFilter("incomplete_order_status_hidden", '\Eccube\Doctrine\Filter\OrderStatusFilter');
796 1067
797 1067
            return $em;
798 1067
        });
799
800 1067
        if (!$this['debug']) {
801 1067
            // second level cacheの設定.
802 1067
            $this->extend(
803 1067
                'orm.em.config',
804
                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...
805
                    $config->setSecondLevelCacheEnabled();
806
                    $cacheConfig = $config->getSecondLevelCacheConfiguration();
807
                    $regionConfig = $cacheConfig->getRegionsConfiguration();
808 1067
                    // TODO キャッシュ先は設定で切り替えられるように
809 1067
                    $cache = $this['orm.cache.factory'](
810
                        'filesystem',
811 1067
                        [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
812
                            'path' => __DIR__.'/../../app/cache/doctrine/second'
813
                        ]
814
                    );
815 1067
                    $factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($regionConfig, $cache);
816
                    $cacheConfig->setCacheFactory($factory);
817
818
                    return $config;
819
                }
820
            );
821
        }
822
    }
823
824
    public function initSecurity()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
825
    {
826
        $this->register(new \Silex\Provider\SecurityServiceProvider());
827
        $this->register(new \Silex\Provider\CsrfServiceProvider());
828
        $this->register(new \Silex\Provider\RememberMeServiceProvider());
829 1067
830 1067
        $this['security.firewalls'] = array(
831
            'admin' => array(
832
                'pattern' => "^/{$this['config']['admin_route']}/",
833 1067
                'form' => array(
834 1067
                    'login_path' => "/{$this['config']['admin_route']}/login",
835
                    'check_path' => "/{$this['config']['admin_route']}/login_check",
836
                    'username_parameter' => 'login_id',
837 1067
                    'password_parameter' => 'password',
838
                    'with_csrf' => true,
839 1067
                    'use_forward' => true,
840
                ),
841
                'logout' => array(
842
                    'logout_path' => "/{$this['config']['admin_route']}/logout",
843
                    'target_url' => "/{$this['config']['admin_route']}/",
844 1067
                ),
845
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Member'),
846 1067
                'anonymous' => true,
847
            ),
848
            'customer' => array(
849
                'pattern' => '^/',
850 1067
                'form' => array(
851 1067
                    'login_path' => '/mypage/login',
852 1067
                    'check_path' => '/login_check',
853 1067
                    'username_parameter' => 'login_email',
854 1067
                    'password_parameter' => 'login_pass',
855 1067
                    'with_csrf' => true,
856 1067
                    'use_forward' => true,
857
                ),
858
                'logout' => array(
859
                    'logout_path' => '/logout',
860 1065
                    'target_url' => '/',
861
                ),
862
                'remember_me' => array(
863 1065
                    'key' => sha1($this['config']['auth_magic']),
864 1065
                    'name' => $this['config']['cookie_name'].'_rememberme',
865 1065
                    // lifetimeはデフォルトの1年間にする
866
                    // 'lifetime' => $this['config']['cookie_lifetime'],
867
                    'path' => $this['config']['root_urlpath'] ?: '/',
868
                    'secure' => $this['config']['force_ssl'],
869 1067
                    'httponly' => true,
870
                    'always_remember_me' => false,
871
                    'remember_me_parameter' => 'login_memory',
872
                ),
873
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Customer'),
874 1065
                'anonymous' => true,
875
            ),
876
        );
877
878 1065
        $channel = null;
879
        // 強制SSL
880 1065
        if ($this['config']['force_ssl'] == \Eccube\Common\Constant::ENABLED) {
881 1067
            $channel = "https";
882
        }
883
884 1065
        $this['security.access_rules'] = array(
885
            array("^/{$this['config']['admin_route']}/login", 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
886
            array("^/{$this['config']['admin_route']}/", 'ROLE_ADMIN', $channel),
887 1067
            array('^/mypage/login', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
888
            array('^/mypage/withdraw_complete', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
889
            array('^/mypage/change', 'IS_AUTHENTICATED_FULLY', $channel),
890
            array('^/mypage', 'ROLE_USER', $channel),
891
        );
892
893 1067
        $this['eccube.password_encoder'] = function ($app) {
894
            return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
895 1067
        };
896 1067
        $this['security.encoder_factory'] = function ($app) {
897
            return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
898
                'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
899
                'Eccube\Entity\Member' => $app['eccube.password_encoder'],
900
            ));
901 1067
        };
902
        $this['eccube.event_listner.security'] = function ($app) {
903
            return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
904
        };
905
906 1065
        // Voterの設定
907
        $this['authority_voter'] = function ($app) {
908 1065
            return new \Eccube\Security\Voter\AuthorityVoter($app);
909
        };
910
911 1065
        $this->extend('security.voters', function ($voters, \Silex\Application $app) {
912
            $voters[] = $app['authority_voter'];
913
914 1065
            return $voters;
915
        });
916
917
        $this['security.access_manager'] = function ($app) {
918
            return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
919 1065
        };
920
921
        $this->on(\Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN, array($this['eccube.event_listner.security'], 'onInteractiveLogin'));
922
    }
923
924
    /**
925
     * ロードバランサー、プロキシサーバの設定を行う
926
     */
927 1057
    public function initProxy()
928
    {
929 1057
        $config = $this['config'];
930
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
931
            $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($config) {
932
                // サブリクエストのREMOTE_ADDRも動的に設定を行う必要があるため、KernelEvents::REQUESTを使用する
933
                Request::setTrustedProxies(array_merge(array($event->getRequest()->server->get('REMOTE_ADDR')), $config['trusted_proxies']));
934
            }, self::EARLY_EVENT);
935 View Code Duplication
        } elseif (isset($config['trusted_proxies']) && !empty($config['trusted_proxies'])) {
936
            Request::setTrustedProxies($config['trusted_proxies']);
937 319
        }
938
    }
939 319
940
    public function initializePlugin()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
941
    {
942
        if ($this->initializedPlugin) {
943
            return;
944
        }
945
        $this->register(new ServiceProvider\EccubePluginServiceProvider());
946
947
        // TODO Acme\ServiceProvider の初期化はここで OK?
948
        if (array_key_exists('service',$this['config'])) {
0 ignored issues
show
introduced by
Add a single space after each comma delimiter
Loading history...
949
            foreach ($this['config']['service'] as $service) {
950
                $this->register(new $service);
0 ignored issues
show
introduced by
Use parentheses when instantiating classes
Loading history...
951
            }
952 1067
        }
953
        $this->initializedPlugin = true;
954 1067
    }
955 1067
956
    /**
957
     * PHPUnit を実行中かどうかを設定する.
958
     *
959
     * @param boolean $testMode PHPUnit を実行中の場合 true
960
     */
961
    public function setTestMode($testMode)
962
    {
963
        $this->testMode = $testMode;
964
    }
965
966
    /**
967
     * PHPUnit を実行中かどうか.
968
     *
969
     * @return boolean PHPUnit を実行中の場合 true
970
     */
971
    public function isTestMode()
972
    {
973
        return $this->testMode;
974
    }
975
976
    /**
977
     *
978
     * データベースの接続を確認
979
     * 成功 : trueを返却
980
     * 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
981
     * 備考 : app['debug']がtrueの際は処理を行わない
982
     *
983
     * @return boolean true
984
     *
985
     */
986
    protected function checkDatabaseConnection()
987
    {
988
        if ($this['debug']) {
989
            return;
990 1068
        }
991
        try {
992 1068
            $this['db']->connect();
993 1068
        } catch (\Doctrine\DBAL\DBALException $e) {
994
            $this['monolog']->error($e->getMessage());
995 1068
            $this['twig.path'] = array(__DIR__.'/Resource/template/exception');
996 1068
            $html = $this['twig']->render('error.twig', array(
997 1068
                'error_title' => 'データーベース接続エラー',
998 1068
                'error_message' => 'データーベースを確認してください',
999
            ));
1000
            $response = new Response();
1001
            $response->setContent($html);
1002 1068
            $response->setStatusCode('500');
1003
            $response->headers->set('Content-Type', 'text/html');
1004 1068
            $response->send();
1005 1068
            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...
1006
        }
1007 1068
1008 1068
        return true;
1009
    }
1010
1011
    /**
1012 1068
     * Config ファイルをパースし、連想配列を返します.
1013 1068
     *
1014
     * $config_name.yml ファイルをパースし、連想配列を返します.
1015 1068
     * $config_name.php が存在する場合は、 PHP ファイルに記述された連想配列を使用します。
1016 1068
     *
1017
     * @param string $config_name Config 名称
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
1018 1068
     * @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...
1019
     * @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...
1020
     * @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...
1021 1068
     * @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...
1022
     * @return Application
1023
     */
1024
    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...
1025
    {
1026
        $ymlPath = $ymlPath ? $ymlPath : __DIR__.'/../../app/config/eccube';
1027
        $distPath = $distPath ? $distPath : __DIR__.'/../../src/Eccube/Resource/config';
1028
1029
        $config = [];
1030 1067
        $config_php = $ymlPath.'/'.$config_name.'.php';
1031
        if (file_exists($config_php)) {
1032 1067
            $config = require $config_php;
1033 1067
        }
1034 1067
1035
        // `%ROOT_DIR%`を絶対パスに変換
1036
        $rootDir = realpath(__DIR__.'/../../');
1037
        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...
1038
            $value = str_replace('%ROOT_DIR%', $rootDir, $value);
1039
        });
1040
1041
        $config_php_dist = $distPath.'/'.$config_name.'.php';
1042
        $config_dist = require $config_php_dist;
1043
1044
        // `%ROOT_DIR%`を絶対パスに変換
1045
        array_walk($config_dist, function(&$value) use ($rootDir) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
1046 1067
            $value = str_replace('%ROOT_DIR%', $rootDir, $value);
1047
        });
1048
1049 1067
        if ($wrap_key) {
1050 1067
            $configAll = array_replace_recursive($configAll, array($config_name => $config_dist), array($config_name => $config));
1051
        } else {
1052
            $configAll = array_replace_recursive($configAll, $config_dist, $config);
1053
        }
1054
1055
        return $this;
1056
    }
1057
1058
    /**
1059
     * セッションが開始されているかどうか.
1060
     *
1061
     * @return boolean セッションが開始済みの場合 true
1062
     * @link http://php.net/manual/ja/function.session-status.php#113468
1063
     */
1064
    protected function isSessionStarted()
1065
    {
1066
        if (php_sapi_name() !== 'cli') {
1067
            if (version_compare(phpversion(), '5.4.0', '>=')) {
1068
                return session_status() === PHP_SESSION_ACTIVE ? true : false;
1069
            } else {
1070
                return session_id() === '' ? false : true;
1071
            }
1072
        }
1073
1074
        return false;
1075
    }
1076
1077
    /**
1078
     * Http Cache対応
1079
     */
1080
    protected function initCacheRequest()
1081
    {
1082
        // httpキャッシュが無効の場合はイベント設定を行わない.
1083
        if (!$this['config']['http_cache']['enabled']) {
1084
            return;
1085
        }
1086
1087
        $app = $this;
1088
1089
        // Response Event(http cache対応、event実行は一番遅く設定)
1090
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
1091
1092
            if (!$event->isMasterRequest()) {
1093
                return;
1094
            }
1095
1096
            $request = $event->getRequest();
1097
            $response = $event->getResponse();
1098
1099
            $route = $request->attributes->get('_route');
1100
1101
            $etag = md5($response->getContent());
1102
1103
            if (strpos($route, 'admin') === 0) {
1104
                // 管理画面
1105
1106
                // 管理画面ではコンテンツの中身が変更された時点でキャッシュを更新し、キャッシュの適用範囲はprivateに設定
1107
                $response->setCache(array(
1108
                    'etag' => $etag,
1109
                    'private' => true,
1110
                ));
1111
1112
                if ($response->isNotModified($request)) {
1113
                    return $response;
1114
                }
1115
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1116
            } else {
1117
                // フロント画面
1118
                $cacheRoute = $app['config']['http_cache']['route'];
1119
1120
                if (in_array($route, $cacheRoute) === true) {
1121
                    // キャッシュ対象となる画面lが含まれていた場合、キャッシュ化
1122
                    // max-ageを設定しているためExpiresは不要
1123
                    // Last-Modifiedだと比較する項目がないためETagで対応
1124
                    // max-ageを設定していた場合、contentの中身が変更されても変更されない
1125
1126
                    $age = $app['config']['http_cache']['age'];
1127
1128
                    $response->setCache(array(
1129
                        'etag' => $etag,
1130
                        'max_age' => $age,
1131
                        's_maxage' => $age,
1132
                        'public' => true,
1133
                    ));
1134
1135
                    if ($response->isNotModified($request)) {
1136
                        return $response;
1137
                    }
1138
                }
1139
            }
1140
1141
        }, -1024);
1142
    }
1143
}
1144