Failed Conditions
Push — experimental/3.1 ( 243c6b...0c67c0 )
by Yangsin
65:47
created

Application   F

Complexity

Total Complexity 112

Size/Duplication

Total Lines 1010
Duplicated Lines 3.37 %

Coupling/Cohesion

Components 2
Dependencies 89

Test Coverage

Coverage 76.67%

Importance

Changes 0
Metric Value
dl 34
loc 1010
ccs 332
cts 433
cp 0.7667
rs 0.9913
c 0
b 0
f 0
wmc 112
lcom 2
cbo 89

22 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 8 2
A clearInstance() 0 4 1
A __clone() 0 4 1
A __construct() 0 14 2
A isBooted() 0 4 1
B initConfig() 0 25 2
A initLogger() 0 5 1
C initialize() 22 185 12
B initLocale() 0 29 5
B initSession() 0 24 3
D initRendering() 0 140 20
C initMailer() 0 29 8
F initDoctrine() 3 176 14
B initSecurity() 0 99 3
B initProxy() 3 12 5
A initializePlugin() 0 8 2
A setTestMode() 0 4 1
A isTestMode() 0 4 1
B checkDatabaseConnection() 0 24 3
D parseConfig() 6 47 13
B isSessionStarted() 0 12 5
B initCacheRequest() 0 63 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Application often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Application, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
namespace Eccube;
25
26
use Doctrine\Common\Annotations\AnnotationReader;
27
use Doctrine\Common\Annotations\CachedReader;
28
use Doctrine\Common\Cache\ArrayCache;
29
use Doctrine\DBAL\Types\Type;
30
use Eccube\Doctrine\DBAL\Types\UTCDateTimeType;
31
use Eccube\Doctrine\DBAL\Types\UTCDateTimeTzType;
32
use Eccube\Doctrine\EventSubscriber\InitSubscriber;
33
use Eccube\Doctrine\ORM\Mapping\Driver\AnnotationDriver;
34
use Eccube\Plugin\ConfigManager as PluginConfigManager;
35
use Eccube\Routing\EccubeRouter;
36
use Eccube\ServiceProvider\EntityEventServiceProvider;
37
use Eccube\ServiceProvider\MobileDetectServiceProvider;
38
use Sergiors\Silex\Routing\ChainUrlGenerator;
39
use Sergiors\Silex\Routing\ChainUrlMatcher;
40
use Symfony\Component\Dotenv\Dotenv;
41
use Symfony\Component\Finder\Finder;
42
use Symfony\Component\HttpFoundation\Request;
43
use Symfony\Component\HttpFoundation\Response;
44
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
45
use Symfony\Component\HttpKernel\KernelEvents;
46
use Symfony\Component\Yaml\Yaml;
47
48
class Application extends \Silex\Application
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
49
{
50
    use \Silex\Application\FormTrait;
51
    use \Silex\Application\UrlGeneratorTrait;
52
    use \Silex\Application\MonologTrait;
53
    use \Silex\Application\SwiftmailerTrait;
54
    use \Silex\Application\SecurityTrait;
55
    use \Silex\Application\TranslationTrait;
56
    use \Eccube\Application\ApplicationTrait;
57
    use \Eccube\Application\SecurityTrait;
58
    use \Eccube\Application\TwigTrait;
59
60
    protected static $instance;
61
62
    protected $initialized = false;
63
    protected $initializedPlugin = false;
64
    protected $testMode = false;
65
66
    public static function getInstance(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
67 1179
    {
68
        if (!is_object(self::$instance)) {
69 1179
            self::$instance = new Application($values);
70 1178
        }
71
72
        return self::$instance;
73 1179
    }
74
75
    public static function clearInstance()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
76 1179
    {
77
        self::$instance = null;
78 1179
    }
79
80
    final public function __clone()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
81
    {
82
        throw new \Exception('Clone is not allowed against '.get_class($this));
83
    }
84
85
    public function __construct(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
86 1179
    {
87
        parent::__construct($values);
88 1179
89
        if (is_null(self::$instance)) {
90 1179
            self::$instance = $this;
91 1179
        }
92
93
        // load config
94
        $this->initConfig();
95 1179
96
        // init monolog
97
        $this->initLogger();
98 1179
    }
99
100
    /**
101
     * Application::runが実行されているか親クラスのプロパティから判定
102
     *
103
     * @return bool
104
     */
105
    public function isBooted()
106 1187
    {
107
        return $this->booted;
108 1187
    }
109
110
    public function initConfig()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
111 1179
    {
112
        // load .env
113
        $envFile = __DIR__.'/../../.env';
114
        if (file_exists($envFile)) {
115 1179
            (new Dotenv())->load($envFile);
116 1179
        }
117 1179
118 1179
        // load config
119 1179
        $this['config'] = function() {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
120 1179
            $configAll = array();
121 1179
            $this->parseConfig('constant', $configAll)
122 1179
                ->parseConfig('path', $configAll)
123 1179
                ->parseConfig('config', $configAll)
124 1179
                ->parseConfig('database', $configAll)
125 1179
                ->parseConfig('mail', $configAll)
126
                ->parseConfig('log', $configAll)
127 1179
                ->parseConfig('nav', $configAll, true)
128
                ->parseConfig('doctrine_cache', $configAll)
129
                ->parseConfig('http_cache', $configAll)
130
                ->parseConfig('session_handler', $configAll);
131 1179
132
            return $configAll;
133 1179
        };
134 1179
    }
135
136
    public function initLogger()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
137 1179
    {
138
        $app = $this;
139 1179
        $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...
140 4
    }
141
142
    public function initialize()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
143
    {
144 1179
        if ($this->initialized) {
145
            return;
146
        }
147 1179
148 1179
        // init locale
149
        $this->initLocale();
150
151
        // init session
152 1179
        if (!$this->isSessionStarted()) {
153
            $this->initSession();
154
        }
155 1179
156 1179
        // init twig
157
        $this->initRendering();
158 1179
159 1179
        // init provider
160 1179
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
161 1179
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
162
        ));
163
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
164 33
        $this->register(new \Silex\Provider\FormServiceProvider());
165 33
        $this->register(new \Silex\Provider\SerializerServiceProvider());
166
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
167
        $this->register(new \Saxulum\Validator\Provider\SaxulumValidatorProvider());
168
        $this->register(new MobileDetectServiceProvider());
169
170
        $this->error(function (\Exception $e, Request $request, $code) {
171
            if ($this['debug']) {
172
                return;
173
            }
174
175
            switch ($code) {
176
                case 403:
177
                    $title = 'アクセスできません。';
178
                    $message = 'お探しのページはアクセスができない状況にあるか、移動もしくは削除された可能性があります。';
179
                    break;
180
                case 404:
181
                    $title = 'ページがみつかりません。';
182
                    $message = 'URLに間違いがないかご確認ください。';
183
                    break;
184
                default:
185
                    $title = 'システムエラーが発生しました。';
186
                    $message = '大変お手数ですが、サイト管理者までご連絡ください。';
187 1179
                    break;
188
            }
189
190 1179
            return $this->render('error.twig', array(
191
                'error_title' => $title,
192
                'error_message' => $message,
193 1179
            ));
194
        });
195
196 1179
        // init mailer
197
        $this->initMailer();
198
199 1179
        // init doctrine orm
200
        $this->initDoctrine();
201 1179
202 1179
        // Set up the DBAL connection now to check for a proper connection to the database.
203 1179
        $this->checkDatabaseConnection();
204 1179
205 1179
        // init security
206 1179
        $this->initSecurity();
207 1179
208
        $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...
209 1179
            'routing.cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/routing'
210 1179
        ]);
211
        $this->register(new \Sergiors\Silex\Provider\DoctrineCacheServiceProvider());
212
        $this->register(new \Sergiors\Silex\Provider\TemplatingServiceProvider());
213 1179
        $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...
214
            'annotations.debug' => $this['debug'],
215
            'annotations.options' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
216
                'cache_driver' => $this['debug'] ? 'array' : 'filesystem',
217 1179
                'cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/annotation'
218
            ]
219
        ]);
220 1179
        $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...
221
            'request' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
222
                'auto_convert' => true
223 1179
            ]
224 1179
        ]);
225 1179
        // init proxy
226 1179
        $this->initProxy();
227
228
        // init ec-cube service provider
229
        $this->register(new ServiceProvider\EccubeServiceProvider());
230 1179
231
        // mount controllers
232
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
233 1178
        $this->mount('', new ControllerProvider\FrontControllerProvider());
0 ignored issues
show
Documentation introduced by
new \Eccube\ControllerPr...ontControllerProvider() is of type object<Eccube\Controller...rontControllerProvider>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
234 1178
        $this->mount('/'.trim($this['config']['admin_route'], '/').'/', new ControllerProvider\AdminControllerProvider());
0 ignored issues
show
Documentation introduced by
new \Eccube\ControllerPr...minControllerProvider() is of type object<Eccube\Controller...dminControllerProvider>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
235 1178
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
236 1178
237 1178
        // ルーティングの設定
238 1178
        // TODO EccubeRoutingServiceProviderに移植する.
239
        $app = $this;
240 1178
        $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...
241 1178
            $options = [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
242
                'debug' => $app['debug'],
243
                'cache_dir' => $app['routing.cache_dir'],
244 1178
                'matcher_base_class' => $app['request_matcher_class'],
245 1178
                'matcher_class' => $app['request_matcher_class'],
246
                'matcher_cache_class' => $cachePrefix.'UrlMatcher',
247
                'generator_cache_class' => $cachePrefix.'UrlGenerator'
248 1178
            ];
249 1178
            $router = new EccubeRouter(
250 1178
                $app['routing.loader'],
251
                $resoure,
252 1178
                $options,
253 1179
                $app['request_context'],
254
                $app['logger']
255
            );
256 1178
257 1178
            $router->setAdminPrefix($app['config']['admin_route']);
258
            $router->setUserDataPrefix($app['config']['user_data_route']);
259 1178
            $router->setRequireHttps($app['config']['force_ssl']);
260
261
            return $router;
262
        });
263
264 1178
        $this['eccube.router.origin'] = function ($app) {
265 1178
            $resource = __DIR__.'/Controller';
266 1178
            $cachePrefix = 'Origin';
267 1178
268
            return $app['eccube.router']($resource, $cachePrefix);
269 1178
        };
270 1178
271 1178
        $this['eccube.routers.plugin'] = function ($app) {
272 1178
            // TODO 有効なプラグインを対象とする必要がある.
273 1178
            $dirs = Finder::create()
274
                ->in($app['config']['root_dir'].'/app/Plugin')
275
                ->name('Controller')
276 1178
                ->directories();
277
278
            $routers = [];
279
            foreach ($dirs as $dir) {
280
                $realPath = $dir->getRealPath();
281 1178
                $pluginCode = basename(dirname($realPath));
282 1178
                $routers[] = $app['eccube.router']($realPath, 'Plugin'.$pluginCode);
283
            }
284 1178
285
            return $routers;
286 1178
        };
287
288
        $this['eccube.router.extend'] = function ($app) {
289
            // TODO ディレクトリ名は暫定
290 1178
            $resource = $app['config']['root_dir'].'/app/Acme/Controller';
291 1178
            $cachePrefix = 'Extend';
292 1178
293 1178
            $router = $app['eccube.router']($resource, $cachePrefix);
294
295 1178
            return $router;
296 1178
        };
297
298 1178 View Code Duplication
        $this->extend('request_matcher', function ($matcher, $app) {
299 1179
            $matchers = [];
300
            $matchers[] = $app['eccube.router.extend'];
301
            foreach ($app['eccube.routers.plugin'] as $router) {
302 1178
                $matchers[] = $router;
303 1178
            };
304 1178
            $matchers[] = $app['eccube.router.origin'];
305 1178
            $matchers[] = $matcher;
306
307 1178
            return new ChainUrlMatcher($matchers, $app['request_context']);
308 1178
        });
309
310 1178 View Code Duplication
        $this->extend('url_generator', function ($generator, $app) {
311 1179
            $generators = [];
312
            $generators[] = $app['eccube.router.extend'];
313
            foreach ($app['eccube.routers.plugin'] as $router) {
314 1179
                $generators[] = $router;
315
            };
316 1179
            $generators[] = $app['eccube.router.origin'];
317
            $generators[] = $generator;
318
319 1179
            return new ChainUrlGenerator($generators, $app['request_context']);
320
        });
321
322
        // init http cache
323 1179
        $this->initCacheRequest();
324 1179
325
        $this->initialized = true;
326
    }
327 1179
328 1179
    public function initLocale()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
329 1179
    {
330
331
        // timezone
332
        if (!empty($this['config']['timezone'])) {
333 1178
            date_default_timezone_set($this['config']['timezone']);
334
        }
335 1178
336 1178
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
337 1178
            'locale' => $this['config']['locale'],
338
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
339
            'locale_fallbacks' => ['ja', 'en'],
340 1178
        ));
341 1178
        $this->extend('translator', function ($translator, \Silex\Application $app) {
342 1178
            $translator->addLoader('yaml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
343
344
            $file = __DIR__.'/Resource/locale/validator.'.$app['locale'].'.yml';
345 1178
            if (file_exists($file)) {
346 1179
                $translator->addResource('yaml', $file, $app['locale'], 'validators');
347
            }
348
349 1179
            $file = __DIR__.'/Resource/locale/message.'.$app['locale'].'.yml';
350
            if (file_exists($file)) {
351 1179
                $translator->addResource('yaml', $file, $app['locale']);
352 1179
            }
353
354 1179
            return $translator;
355 1179
        });
356 1179
    }
357 1179
358
    public function initSession()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
359
    {
360
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
361
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
362
            'session.storage.options' => array(
363
                'name' => $this['config']['cookie_name'],
364 1179
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
365
                'cookie_secure' => $this['config']['force_ssl'],
366 1179
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
367
                'cookie_httponly' => true,
368
                // cookie_domainは指定しない
369
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
370
            ),
371
        ));
372
373
        $options = $this['config']['session_handler'];
374 1179
375
        if ($options['enabled']) {
376 1179
            // @see http://silex.sensiolabs.org/doc/providers/session.html#custom-session-configurations
377 1179
            $this['session.storage.handler'] = null;
378
            ini_set('session.save_handler', $options['save_handler']);
379
            ini_set('session.save_path', $options['save_path']);
380 1178
        }
381 1178
    }
382
383 1178
    public function initRendering()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
384 1179
    {
385
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
386
            'twig.form.templates' => array('Form/form_layout.twig'),
387 475
        ));
388 475
        $this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
389 475
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
390 475
            $twig->addExtension(new \Twig_Extension_StringLoader());
391 300
392
            return $twig;
393 177
        });
394
395 475
        $this->before(function (Request $request, \Silex\Application $app) {
396 300
            $app['admin'] = $app['front'] = false;
397 300
            $pathinfo = rawurldecode($request->getPathInfo());
398
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
399 300
                $app['admin'] = true;
400 300
            } else {
401
                $app['front'] = true;
402
            }
403
404 177
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
405 177
            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...
406
                if (file_exists(__DIR__.'/../../app/template/admin')) {
407 177
                    $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...
408 177
                }
409
                $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...
410 177
                $paths[] = __DIR__.'/../../app/Plugin';
411
                $cacheDir =  __DIR__.'/../../app/cache/twig/admin';
412
            } else {
413 475
                // モバイル端末時、smartphoneディレクトリを探索パスに追加する.
414
                if ($app['mobile_detect.device_type'] == \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_SP) {
415
                    if (file_exists(__DIR__.'/../../app/template/smartphone')) {
416 475
                        $paths[] = __DIR__.'/../../app/template/smartphone';
417
                    }
418
                    $paths[] = __DIR__.'/Resource/template/smartphone';
419
                }
420
421
                if (file_exists($app['config']['template_realdir'])) {
422
                    $paths[] = $app['config']['template_realdir'];
423
                }
424
                $paths[] = $app['config']['template_default_realdir'];
425
                $paths[] = __DIR__.'/../../app/Plugin';
426
                $cacheDir =  __DIR__.'/../../app/cache/twig/'.$app['config']['template_code'];
427
            }
428
            $app['twig']->setCache($app['debug'] ? null : $cacheDir);
429
            $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
430
431
            // 管理画面のIP制限チェック.
432
            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...
433
                // IP制限チェック
434
                $allowHost = $app['config']['admin_allow_host'];
435
                if (count($allowHost) > 0) {
436
                    if (array_search($app['request_stack']->getCurrentRequest()->getClientIp(), $allowHost) === false) {
437
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
438
                    }
439
                }
440
            }
441
        }, self::EARLY_EVENT);
442
443
        // twigのグローバル変数を定義.
444
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) {
445
            // 未ログイン時にマイページや管理画面以下にアクセスするとSubRequestで実行されるため,
446
            // $event->isMasterRequest()ではなく、グローバル変数が初期化済かどうかの判定を行う
447
            if (isset($this['twig_global_initialized']) && $this['twig_global_initialized'] === true) {
448
                return;
449
            }
450
            // ショップ基本情報
451
            $BaseInfo = $this['eccube.repository.base_info']->get();
452
            $this['twig']->addGlobal('BaseInfo', $BaseInfo);
453 475
454
            if ($this->isAdminRequest()) {
455 300
                // 管理画面
456 300
                // 管理画面メニュー
457
                $menus = array('', '', '');
458
                $this['twig']->addGlobal('menus', $menus);
459
460
                $Member = $this->user();
461
                if (is_object($Member)) {
462 1179
                    // ログインしていれば管理者のロールを取得
463
                    $AuthorityRoles = $this['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
464
465
                    $roles = array();
466
                    $request = $event->getRequest();
467
                    foreach ($AuthorityRoles as $AuthorityRole) {
468 470
                        // 管理画面でメニュー制御するため相対パス全てをセット
469 122
                        $roles[] = $request->getBaseUrl().'/'.$this['config']['admin_route'].$AuthorityRole->getDenyUrl();
470
                    }
471
472 470
                    $this['twig']->addGlobal('AuthorityRoles', $roles);
473 470
                }
474
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
475 470
            } else {
476
                // フロント画面
477
                $request = $event->getRequest();
478 300
                $route = $request->attributes->get('_route');
479 300
480
                // ユーザ作成画面
481 300
                if ($route === 'user_data') {
482 300
                    $params = $request->attributes->get('_route_params');
483
                    $route = $params['route'];
484 294
                    // プレビュー画面
485
                } elseif ($request->get('preview')) {
486 294
                    $route = 'preview';
487 294
                }
488 294
489
                try {
490 294
                    $device_type_id = $this['mobile_detect.device_type'];
491
492
                    // TODO デバッグ用
493 300
                    if ($request->query->has('device_type_id')) {
494
                        $device_type_id = $request->get('device_type_id', \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
495
                    }
496
497
                    $DeviceType = $this['eccube.repository.master.device_type']
498 170
                        ->find($device_type_id);
499 170
                    $qb = $this['eccube.repository.page_layout']->createQueryBuilder('p');
500
                    $PageLayout = $qb->select('p, pll,l, bp, b')
501
                        ->leftJoin('p.PageLayoutLayouts', 'pll')
502 170
                        ->leftJoin('pll.Layout', 'l')
503 2
                        ->leftJoin('l.BlockPositions', 'bp')
504 2
                        ->leftJoin('bp.Block', 'b')
505
                        ->where('p.url = :route')
506 168
                        ->andWhere('l.DeviceType = :DeviceType')
507
                        ->orderBy('bp.block_row', 'ASC')
508
                        ->setParameter('route', $route)
509
                        ->setParameter('DeviceType', $DeviceType)
510
                        ->getQuery()
511 170
                        ->getSingleResult();
512 170
                } catch (\Doctrine\ORM\NoResultException $e) {
513 170
                    $PageLayout = $this['eccube.repository.page_layout']->newPageLayout($DeviceType);
0 ignored issues
show
Bug introduced by
The variable $DeviceType does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
514 69
                }
515 69
516
                $this['twig']->addGlobal('PageLayout', $PageLayout);
517
                $this['twig']->addGlobal('title', $PageLayout->getName());
518 170
            }
519 170
520
            $this['twig_global_initialized'] = true;
521
        });
522 470
    }
523 1179
524
    public function initMailer()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
525
    {
526 1179
527
        // メール送信時の文字エンコード指定(デフォルトはUTF-8)
528
        if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
529
            if ($this['config']['mail']['charset_iso_2022_jp'] === true) {
530 1179
                \Swift::init(function () {
531 1179
                    \Swift_DependencyContainer::getInstance()
532
                        ->register('mime.qpheaderencoder')
533
                        ->asAliasOf('mime.base64headerencoder');
534
                    \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
535
                });
536
            }
537
        }
538
539
        $this->register(new \Silex\Provider\SwiftmailerServiceProvider());
540
        $this['swiftmailer.options'] = $this['config']['mail'];
541 1179
542 1179
        if (isset($this['config']['mail']['spool']) && is_bool($this['config']['mail']['spool'])) {
543
            $this['swiftmailer.use_spool'] = $this['config']['mail']['spool'];
544 1179
        }
545 1179
        // デフォルトはsmtpを使用
546
        $transport = $this['config']['mail']['transport'];
547
        if ($transport == 'sendmail') {
548 1179
            $this['swiftmailer.transport'] = \Swift_SendmailTransport::newInstance();
549 1179
        } elseif ($transport == 'mail') {
550
            $this['swiftmailer.transport'] = \Swift_MailTransport::newInstance();
551 1179
        }
552
    }
553
554
    public function initDoctrine()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
555
    {
556 1179
        $this->register(new EntityEventServiceProvider());
557
        $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...
558 1179
            'dbs.options' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
559 1179
                'default' => $this['config']['database']
560
            )
561 1179
        ));
562
        $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Provider\DoctrineOrmManagerRegistryProvider());
563
564
        $app = $this;
565 1179
        $this->extend('db.event_manager', function ($evm) use ($app) {
566 1179
            $initSubscriber = new InitSubscriber($app);
567
            $evm->addEventSubscriber($initSubscriber);
568
569
            return $evm;
570 1179
        });
571 1179
572 1179
        // UTCで保存
573
        // @see http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/cookbook/working-with-datetime.html
574
        UTCDateTimeType::setTimeZone($this['config']['timezone']);
575
        UTCDateTimeTzType::setTimeZone($this['config']['timezone']);
576
        Type::overrideType('datetime', UTCDateTimeType::class);
577
        Type::overrideType('datetimetz', UTCDateTimeTzType::class);
578
579
        // プラグインのmetadata定義を合わせて行う.
580
        $pluginConfigs = PluginConfigManager::getPluginConfigAll($this['debug']);
581
        $ormMappings = array();
582
        $ormMappings[] = array(
583
             'type' => 'annotation',
584
             'namespace' => 'Eccube\Entity',
585
             'path' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
586
                 __DIR__.'/Entity'
587
             ),
588
             'use_simple_annotation_reader' => false,
589
         );
590
591
        // TODO namespace は暫定
592
        $ormMappings[] = array(
593 1179
            'type' => 'annotation',
594
            'namespace' => 'Acme\Entity',
595
            'path' => array(
596
                __DIR__.'/../../app/Acme/Entity',
597
            ),
598
            'use_simple_annotation_reader' => false,
599
        );
600
601
        foreach ($pluginConfigs as $code) {
602 1179
            $config = $code['config'];
603 1179
            // Doctrine Extend
604
            if (isset($config['orm.path']) && is_array($config['orm.path'])) {
605 1179
                $paths = array();
606 1179 View Code Duplication
                foreach ($config['orm.path'] as $path) {
607 1179
                    $paths[] = $this['config']['plugin_realdir'].'/'.$config['code'].$path;
608 1179
                }
609
                $ormMappings[] = array(
610 1179
                    'type' => 'yml',
611 1179
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
612 1179
                    'path' => $paths,
613 1179
                );
614
                $ormMappings[] = array(
615 1179
                    'type' => 'annotation',
616 1179
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
617 1179
                    'path' => $paths,
618 1179
                    'use_simple_annotation_reader' => false,
619
                );
620
            }
621
        }
622
623
        $options = array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
624
            'mappings' => $ormMappings
625 1179
        );
626
627
        if (!$this['debug']) {
628 1179
            $cacheDrivers = array();
629
            if (array_key_exists('doctrine_cache', $this['config'])) {
630
                $cacheDrivers = $this['config']['doctrine_cache'];
631
            }
632
633
            if (array_key_exists('metadata_cache', $cacheDrivers)) {
634
                $options['metadata_cache'] = $cacheDrivers['metadata_cache'];
635
            }
636
            if (array_key_exists('query_cache', $cacheDrivers)) {
637
                $options['query_cache'] = $cacheDrivers['query_cache'];
638
            }
639
            if (array_key_exists('result_cache', $cacheDrivers)) {
640
                $options['result_cache'] = $cacheDrivers['result_cache'];
641
            }
642
            if (array_key_exists('hydration_cache', $cacheDrivers)) {
643
                $options['hydration_cache'] = $cacheDrivers['hydration_cache'];
644
            }
645
        }
646
647
        $this->register(new \Dflydev\Provider\DoctrineOrm\DoctrineOrmServiceProvider(), array(
648 1179
            'orm.proxies_dir' => __DIR__.'/../../app/cache/doctrine/proxies',
649 1179
            'orm.em.options' => $options,
650 1179
            'orm.custom.functions.string' => array(
651 1179
                'NORMALIZE' => 'Eccube\Doctrine\ORM\Query\Normalize',
652
            ),
653
            'orm.custom.functions.numeric' => array(
654
                'EXTRACT' => 'Eccube\Doctrine\ORM\Query\Extract',
655
            ),
656
        ));
657
658
        $this->extend(
659
            'orm.em.config',
660
            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...
661 1179
662 1179
                /** @var $chain \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain */
663 1179
                $chain = $config->getMetadataDriverImpl();
664 1179
                $drivers = $chain->getDrivers();
665
                foreach ($drivers as $namespace => $oldDriver) {
666
                    if ('Eccube\Entity' === $namespace) {
667 1179
                        $newDriver = new AnnotationDriver(
668 1179
                            new CachedReader(new AnnotationReader(), new ArrayCache()),
0 ignored issues
show
Documentation introduced by
new \Doctrine\Common\Ann...mon\Cache\ArrayCache()) is of type object<Doctrine\Common\Annotations\CachedReader>, but the function expects a object<Doctrine\Common\A...tions\AnnotationReader>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
669
                            $oldDriver->getPaths());
670
                        $newDriver->setFileExtension($oldDriver->getFileExtension());
671 1179
                        $newDriver->addExcludePaths($oldDriver->getExcludePaths());
672 1179
                        $newDriver->setTraitProxiesDirectory(
673
                            realpath(__DIR__.'/../../app/proxy/entity'));
674
                        $chain->addDriver($newDriver, $namespace);
675 1179
                    }
676 1179
                }
677 1179
678 1179
                return $config;
679 1179
            }
680
        );
681 1179
682 1179
        $this->extend('orm.em', function (\Doctrine\ORM\EntityManager $em, \Silex\Application $app) {
683
            // tax_rule
684
            $taxRuleRepository = $em->getRepository('Eccube\Entity\TaxRule');
685
            $taxRuleRepository->setApplication($app);
686 1179
            $taxRuleService = new \Eccube\Service\TaxRuleService($taxRuleRepository);
0 ignored issues
show
Compatibility introduced by
$taxRuleRepository of type object<Doctrine\ORM\EntityRepository> is not a sub-type of object<Eccube\Repository\TaxRuleRepository>. It seems like you assume a child class of the class Doctrine\ORM\EntityRepository 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...
687
            $em->getEventManager()->addEventSubscriber(new \Eccube\Doctrine\EventSubscriber\TaxRuleEventSubscriber($taxRuleService));
688 1179
689 1179
            // save
690 1179
            $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...
691
            $em->getEventManager()->addEventSubscriber($saveEventSubscriber);
692 1179
693
            // clear cache
694 1179
            $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...
695
            $em->getEventManager()->addEventSubscriber($clearCacheEventSubscriber);
696 1179
697 1179
            // filters
698 1179
            $config = $em->getConfiguration();
699 1179
            $config->addFilter("soft_delete", '\Eccube\Doctrine\Filter\SoftDeleteFilter');
700
            $config->addFilter("nostock_hidden", '\Eccube\Doctrine\Filter\NoStockHiddenFilter');
701
            $config->addFilter("incomplete_order_status_hidden", '\Eccube\Doctrine\Filter\OrderStatusFilter');
702
            $em->getFilters()->enable('soft_delete');
703
704 1179
            return $em;
705 1179
        });
706
707 1179
        if (!$this['debug']) {
708
            // second level cacheの設定.
709 1179
            $this->extend(
710
                'orm.em.config',
711 1179
                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...
712
                    $config->setSecondLevelCacheEnabled();
713
                    $cacheConfig = $config->getSecondLevelCacheConfiguration();
714
                    $regionConfig = $cacheConfig->getRegionsConfiguration();
715
                    // TODO キャッシュ先は設定で切り替えられるように
716
                    $cache = $this['orm.cache.factory'](
717
                        'filesystem',
718
                        [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
719
                            'path' => __DIR__.'/../../app/cache/doctrine/second'
720
                        ]
721
                    );
722
                    $factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($regionConfig, $cache);
723
                    $cacheConfig->setCacheFactory($factory);
724
725 1179
                    return $config;
726 1179
                }
727
            );
728
        }
729 1179
    }
730 1179
731
    public function initSecurity()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
732
    {
733 1179
        $this->register(new \Silex\Provider\SecurityServiceProvider());
734
        $this->register(new \Silex\Provider\CsrfServiceProvider());
735 1179
        $this->register(new \Silex\Provider\RememberMeServiceProvider());
736
737
        $this['security.firewalls'] = array(
738
            'admin' => array(
739
                'pattern' => "^/{$this['config']['admin_route']}/",
740 1179
                'form' => array(
741 1179
                    'login_path' => "/{$this['config']['admin_route']}/login",
742 1179
                    'check_path' => "/{$this['config']['admin_route']}/login_check",
743
                    'username_parameter' => 'login_id',
744
                    'password_parameter' => 'password',
745
                    'with_csrf' => true,
746
                    'use_forward' => true,
747
                ),
748
                'logout' => array(
749
                    'logout_path' => "/{$this['config']['admin_route']}/logout",
750 1175
                    'target_url' => "/{$this['config']['admin_route']}/",
751
                ),
752
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Member'),
753 1175
                'anonymous' => true,
754 1175
            ),
755 1175
            'customer' => array(
756
                'pattern' => '^/',
757
                'form' => array(
758
                    'login_path' => '/mypage/login',
759 1179
                    'check_path' => '/login_check',
760
                    'username_parameter' => 'login_email',
761
                    'password_parameter' => 'login_pass',
762
                    'with_csrf' => true,
763
                    'use_forward' => true,
764 1175
                ),
765
                'logout' => array(
766
                    'logout_path' => '/logout',
767
                    'target_url' => '/',
768 1175
                ),
769
                'remember_me' => array(
770 1175
                    'key' => sha1($this['config']['auth_magic']),
771 1179
                    'name' => $this['config']['cookie_name'].'_rememberme',
772
                    // lifetimeはデフォルトの1年間にする
773
                    // 'lifetime' => $this['config']['cookie_lifetime'],
774 1175
                    'path' => $this['config']['root_urlpath'] ?: '/',
775
                    'secure' => $this['config']['force_ssl'],
776
                    'httponly' => true,
777 1179
                    'always_remember_me' => false,
778
                    'remember_me_parameter' => 'login_memory',
779
                ),
780 1175
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Customer'),
781
                'anonymous' => true,
782 1175
            ),
783
        );
784
785 1175
        $channel = null;
786 1175
        // 強制SSL
787
        if ($this['config']['force_ssl'] == \Eccube\Common\Constant::ENABLED) {
788
            $channel = "https";
789
        }
790
791
        $this['security.access_rules'] = array(
792
            array("^/{$this['config']['admin_route']}/login", 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
793
            array("^/{$this['config']['admin_route']}/", 'ROLE_ADMIN', $channel),
794 1169
            array('^/mypage/login', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
795
            array('^/mypage/withdraw_complete', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
796 1169
            array('^/mypage/change', 'IS_AUTHENTICATED_FULLY', $channel),
797
            array('^/mypage', 'ROLE_USER', $channel),
798
        );
799
800
        $this['eccube.password_encoder'] = function ($app) {
801
            return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
802
        };
803
        $this['security.encoder_factory'] = function ($app) {
804 475
            return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
805
                'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
806 475
                'Eccube\Entity\Member' => $app['eccube.password_encoder'],
807
            ));
808
        };
809
        $this['eccube.event_listner.security'] = function ($app) {
810
            return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
811
        };
812
813
        // Voterの設定
814
        $this['authority_voter'] = function ($app) {
815
            return new \Eccube\Security\Voter\AuthorityVoter($app);
816
        };
817
818
        $this->extend('security.voters', function ($voters, \Silex\Application $app) {
819 1179
            $voters[] = $app['authority_voter'];
820
821 1179
            return $voters;
822 1179
        });
823
824
        $this['security.access_manager'] = function ($app) {
825
            return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
826
        };
827
828
        $this->on(\Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN, array($this['eccube.event_listner.security'], 'onInteractiveLogin'));
829
    }
830
831
    /**
832
     * ロードバランサー、プロキシサーバの設定を行う
833
     */
834
    public function initProxy()
835
    {
836
        $config = $this['config'];
837
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
838
            $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($config) {
839
                // サブリクエストのREMOTE_ADDRも動的に設定を行う必要があるため、KernelEvents::REQUESTを使用する
840
                Request::setTrustedProxies(array_merge(array($event->getRequest()->server->get('REMOTE_ADDR')), $config['trusted_proxies']));
841
            }, self::EARLY_EVENT);
842 View Code Duplication
        } elseif (isset($config['trusted_proxies']) && !empty($config['trusted_proxies'])) {
843
            Request::setTrustedProxies($config['trusted_proxies']);
844
        }
845
    }
846
847
    public function initializePlugin()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
848
    {
849
        if ($this->initializedPlugin) {
850
            return;
851
        }
852
        $this->register(new ServiceProvider\EccubePluginServiceProvider());
853
        $this->initializedPlugin = true;
854
    }
855
856
    /**
857 1179
     * PHPUnit を実行中かどうかを設定する.
858
     *
859 1179
     * @param boolean $testMode PHPUnit を実行中の場合 true
860 1179
     */
861 1179
    public function setTestMode($testMode)
862 1179
    {
863 1179
        $this->testMode = $testMode;
864 1179
    }
865 1179
866 1179
    /**
867 1179
     * PHPUnit を実行中かどうか.
868 1179
     *
869 1179
     * @return boolean PHPUnit を実行中の場合 true
870
     */
871
    public function isTestMode()
872
    {
873
        return $this->testMode;
874
    }
875
876 1179
    /**
877 1179
     *
878 1179
     * データベースの接続を確認
879 1179
     * 成功 : trueを返却
880 1179
     * 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
881 1179
     * 備考 : app['debug']がtrueの際は処理を行わない
882 1179
     *
883 1179
     * @return boolean true
884
     *
885
     */
886
    protected function checkDatabaseConnection()
887
    {
888
        if ($this['debug']) {
889
            return;
890 1179
        }
891 1179
        try {
892
            $this['db']->connect();
893 1179
        } catch (\Doctrine\DBAL\DBALException $e) {
894
            $this['monolog']->error($e->getMessage());
895
            $this['twig.path'] = array(__DIR__.'/Resource/template/exception');
896 1179
            $html = $this['twig']->render('error.twig', array(
897
                'error_title' => 'データーベース接続エラー',
898
                'error_message' => 'データーベースを確認してください',
899
            ));
900
            $response = new Response();
901
            $response->setContent($html);
902
            $response->setStatusCode('500');
903
            $response->headers->set('Content-Type', 'text/html');
904
            $response->send();
905 1179
            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...
906
        }
907 1179
908 1179
        return true;
909 1179
    }
910
911
    /**
912
     * Config ファイルをパースし、連想配列を返します.
913
     *
914
     * $config_name.yml ファイルをパースし、連想配列を返します.
915
     * $config_name.php が存在する場合は、 PHP ファイルに記述された連想配列を使用します。
916
     *
917
     * @param string $config_name Config 名称
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
918
     * @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...
919
     * @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...
920
     * @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...
921 1179
     * @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...
922
     * @return Application
923
     */
924 1179
    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...
925 1179
    {
926
        $ymlPath = $ymlPath ? $ymlPath : __DIR__.'/../../app/config/eccube';
927
        $distPath = $distPath ? $distPath : __DIR__.'/../../src/Eccube/Resource/config';
928
        $config = array();
929
        $config_php = $ymlPath.'/'.$config_name.'.php';
930
        if (!file_exists($config_php)) {
931
            $config_yml = $ymlPath.'/'.$config_name.'.yml';
932
            if (file_exists($config_yml)) {
933
                $config = Yaml::parse(file_get_contents($config_yml));
934
                $config = empty($config) ? array() : $config;
935 View Code Duplication
                if (isset($this['output_config_php']) && $this['output_config_php']) {
936
                    file_put_contents($config_php, sprintf('<?php return %s', var_export($config, true)).';');
937
                }
938
            }
939
        } else {
940
            $config = require $config_php;
941
        }
942
943
        // `%ROOT_DIR%`を絶対パスに変換
944
        $rootDir = realpath(__DIR__.'/../../');
945
        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...
946
            $value = str_replace('%ROOT_DIR%', $rootDir, $value);
947
        });
948
949
        $config_dist = array();
950
        $config_php_dist = $distPath.'/'.$config_name.'.dist.php';
951
        if (!file_exists($config_php_dist)) {
952
            $config_yml_dist = $distPath.'/'.$config_name.'.yml.dist';
953
            if (file_exists($config_yml_dist)) {
954
                $config_dist = Yaml::parse(file_get_contents($config_yml_dist));
955 View Code Duplication
                if (isset($this['output_config_php']) && $this['output_config_php']) {
956
                    file_put_contents($config_php_dist, sprintf('<?php return %s', var_export($config_dist, true)).';');
957
                }
958
            }
959
        } else {
960
            $config_dist = require $config_php_dist;
961
        }
962
963
        if ($wrap_key) {
964
            $configAll = array_replace_recursive($configAll, array($config_name => $config_dist), array($config_name => $config));
965
        } else {
966
            $configAll = array_replace_recursive($configAll, $config_dist, $config);
967
        }
968
969
        return $this;
970
    }
971
972
    /**
973
     * セッションが開始されているかどうか.
974
     *
975
     * @return boolean セッションが開始済みの場合 true
976
     * @link http://php.net/manual/ja/function.session-status.php#113468
977
     */
978
    protected function isSessionStarted()
979
    {
980
        if (php_sapi_name() !== 'cli') {
981
            if (version_compare(phpversion(), '5.4.0', '>=')) {
982
                return session_status() === PHP_SESSION_ACTIVE ? true : false;
983
            } else {
984
                return session_id() === '' ? false : true;
985
            }
986
        }
987
988
        return false;
989
    }
990
991
    /**
992
     * Http Cache対応
993
     */
994
    protected function initCacheRequest()
995
    {
996
        // httpキャッシュが無効の場合はイベント設定を行わない.
997
        if (!$this['config']['http_cache']['enabled']) {
998
            return;
999
        }
1000
1001
        $app = $this;
1002
1003
        // Response Event(http cache対応、event実行は一番遅く設定)
1004
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
1005
1006
            if (!$event->isMasterRequest()) {
1007
                return;
1008
            }
1009
1010
            $request = $event->getRequest();
1011
            $response = $event->getResponse();
1012
1013
            $route = $request->attributes->get('_route');
1014
1015
            $etag = md5($response->getContent());
1016
1017
            if (strpos($route, 'admin') === 0) {
1018
                // 管理画面
1019
1020
                // 管理画面ではコンテンツの中身が変更された時点でキャッシュを更新し、キャッシュの適用範囲はprivateに設定
1021
                $response->setCache(array(
1022
                    'etag' => $etag,
1023
                    'private' => true,
1024
                ));
1025
1026
                if ($response->isNotModified($request)) {
1027
                    return $response;
1028
                }
1029
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1030
            } else {
1031
                // フロント画面
1032
                $cacheRoute = $app['config']['http_cache']['route'];
1033
1034
                if (in_array($route, $cacheRoute) === true) {
1035
                    // キャッシュ対象となる画面lが含まれていた場合、キャッシュ化
1036
                    // max-ageを設定しているためExpiresは不要
1037
                    // Last-Modifiedだと比較する項目がないためETagで対応
1038
                    // max-ageを設定していた場合、contentの中身が変更されても変更されない
1039
1040
                    $age = $app['config']['http_cache']['age'];
1041
1042
                    $response->setCache(array(
1043
                        'etag' => $etag,
1044
                        'max_age' => $age,
1045
                        's_maxage' => $age,
1046
                        'public' => true,
1047
                    ));
1048
1049
                    if ($response->isNotModified($request)) {
1050
                        return $response;
1051
                    }
1052
                }
1053
            }
1054
1055
        }, -1024);
1056
    }
1057
}
1058