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

Application::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2.004

Importance

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