Completed
Pull Request — experimental/3.1 (#2480)
by Kentaro
72:50 queued 16:33
created

Application::getInstance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2
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\CompatRepositoryProvider;
37
use Eccube\ServiceProvider\CompatServiceProvider;
38
use Eccube\ServiceProvider\DiServiceProvider;
39
use Eccube\ServiceProvider\EntityEventServiceProvider;
40
use Eccube\ServiceProvider\MobileDetectServiceProvider;
41
use Sergiors\Silex\Routing\ChainUrlGenerator;
42
use Sergiors\Silex\Routing\ChainUrlMatcher;
43
use Symfony\Component\Dotenv\Dotenv;
44
use Symfony\Component\Finder\Finder;
45
use Symfony\Component\HttpFoundation\Request;
46
use Symfony\Component\HttpFoundation\Response;
47
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
48
use Symfony\Component\HttpKernel\KernelEvents;
49
use Symfony\Component\Yaml\Yaml;
50
51
class Application extends \Silex\Application
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
52
{
53
    use \Silex\Application\FormTrait;
54
    use \Silex\Application\UrlGeneratorTrait;
55
    use \Silex\Application\MonologTrait;
56
    use \Silex\Application\SwiftmailerTrait;
57
    use \Silex\Application\SecurityTrait;
58
    use \Silex\Application\TranslationTrait;
59
    use \Eccube\Application\ApplicationTrait;
60
    use \Eccube\Application\SecurityTrait;
61
    use \Eccube\Application\TwigTrait;
62
63
    protected static $instance;
64
65
    protected $initialized = false;
66
    protected $initializedPlugin = false;
67
    protected $testMode = false;
68
69 1104
    public static function getInstance(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
70
    {
71 1104
        if (!is_object(self::$instance)) {
72 1104
            self::$instance = new Application($values);
73
        }
74
75 1104
        return self::$instance;
76
    }
77
78 1104
    public static function clearInstance()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
79
    {
80 1104
        self::$instance = null;
81
    }
82
83
    final public function __clone()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
84
    {
85
        throw new \Exception('Clone is not allowed against '.get_class($this));
86
    }
87
88 1105
    public function __construct(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
89
    {
90 1105
        parent::__construct($values);
91
92 1105
        if (is_null(self::$instance)) {
93 1105
            self::$instance = $this;
94
        }
95
96
        // load config
97 1105
        $this->initConfig();
98
99
        // init monolog
100 1105
        $this->initLogger();
101
    }
102
103
    /**
104
     * Application::runが実行されているか親クラスのプロパティから判定
105
     *
106
     * @return bool
107
     */
108 1104
    public function isBooted()
109
    {
110 1104
        return $this->booted;
111
    }
112
113 1105
    public function initConfig()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
114
    {
115
        // load .env
116 1105
        $envFile = __DIR__.'/../../.env';
117 1105
        if (file_exists($envFile)) {
118
            (new Dotenv())->load($envFile);
119
        }
120
121
        // load config
122
        $this['config'] = function() {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
123 1105
            $configAll = array();
124 1105
            $this->parseConfig('constant', $configAll)
125 1105
                ->parseConfig('path', $configAll)
126 1105
                ->parseConfig('config', $configAll)
127 1105
                ->parseConfig('database', $configAll)
128 1105
                ->parseConfig('mail', $configAll)
129 1105
                ->parseConfig('log', $configAll)
130 1105
                ->parseConfig('nav', $configAll, true)
131 1105
                ->parseConfig('doctrine_cache', $configAll)
132 1105
                ->parseConfig('http_cache', $configAll)
133 1105
                ->parseConfig('session_handler', $configAll);
134
135 1105
            return $configAll;
136
        };
137
    }
138
139 1105
    public function initLogger()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
140
    {
141 1105
        $app = $this;
142 1105
        $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...
143
    }
144
145 1104
    public function initialize()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
146
    {
147 1104
        if ($this->initialized) {
148 2
            return;
149
        }
150
151
        // init locale
152 1104
        $this->initLocale();
153
154
        // init session
155 1104
        if (!$this->isSessionStarted()) {
156 1104
            $this->initSession();
157
        }
158
159
        // init twig
160 1104
        $this->initRendering();
161
162
        // init provider
163 1104
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
164 1104
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
165
        ));
166 1104
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
167 1104
        $this->register(new \Silex\Provider\FormServiceProvider());
168 1104
        $this->register(new \Silex\Provider\SerializerServiceProvider());
169 1104
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
170 1104
        $this->register(new \Saxulum\Validator\Provider\SaxulumValidatorProvider());
171 1104
        $this->register(new MobileDetectServiceProvider());
172
173
        $this->error(function (\Exception $e, Request $request, $code) {
174 23
            if ($this['debug']) {
175 23
                return;
176
            }
177
178
            switch ($code) {
179
                case 403:
180
                    $title = 'アクセスできません。';
181
                    $message = 'お探しのページはアクセスができない状況にあるか、移動もしくは削除された可能性があります。';
182
                    break;
183
                case 404:
184
                    $title = 'ページがみつかりません。';
185
                    $message = 'URLに間違いがないかご確認ください。';
186
                    break;
187
                default:
188
                    $title = 'システムエラーが発生しました。';
189
                    $message = '大変お手数ですが、サイト管理者までご連絡ください。';
190
                    break;
191
            }
192
193
            return $this->render('error.twig', array(
194
                'error_title' => $title,
195
                'error_message' => $message,
196
            ));
197 1104
        });
198
199
        // init mailer
200 1104
        $this->initMailer();
201
202 1104
        $this->register(new \Sergiors\Silex\Provider\DoctrineCacheServiceProvider());
203 1104
        $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...
204 1104
            'annotations.debug' => $this['debug'],
205
            'annotations.options' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
206 1104
                'cache_driver' => $this['debug'] ? 'array' : 'filesystem',
207 1104
                'cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/annotation'
208
            ]
209
        ]);
210
211
        // init doctrine orm
212 1104
        $this->initDoctrine();
213
214
        // Set up the DBAL connection now to check for a proper connection to the database.
215 1104
        $this->checkDatabaseConnection();
216
217
        // init security
218 1104
        $this->initSecurity();
219
220 1104
        $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...
221 1104
            'routing.cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/routing'
222
        ]);
223 1104
        $this->register(new \Sergiors\Silex\Provider\TemplatingServiceProvider());
224 1104
        $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...
225 1104
            'request' => [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
226
                'auto_convert' => true
227
            ]
228
        ]);
229
        // init proxy
230 1104
        $this->initProxy();
231
232
        // init ec-cube service provider
233 1104
        $this->register(new DiServiceProvider(), [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
234
            'eccube.di.dirs' => [
235 1104
                $this['config']['root_dir'].'/app/Acme/Controller',
236 1104
                $this['config']['root_dir'].'/src/Eccube/Repository',
237 1104
                $this['config']['root_dir'].'/src/Eccube/Form/Type',
238 1104
                $this['config']['root_dir'].'/src/Eccube/Form/Extension',
239 1104
                $this['config']['root_dir'].'/src/Eccube/Service',
240 1104
                $this['config']['root_dir'].'/src/Eccube/Controller',
241
            ],
242 1104
            'eccube.di.generator.dir' => $this['config']['root_dir'].'/app/cache/provider'
243
        ]);
244
245 1104
        $this->register(new CompatRepositoryProvider());
246 1104
        $this->register(new CompatServiceProvider());
247 1104
        $this->register(new ServiceProvider\EccubeServiceProvider());
248
249 1104
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
250 1104
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
251
252
        // ルーティングの設定
253
        // TODO EccubeRoutingServiceProviderに移植する.
254 1104
        $app = $this;
255
        $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...
256
            $options = [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
257 1104
                'debug' => $app['debug'],
258 1104
                'cache_dir' => $app['routing.cache_dir'],
259 1104
                'matcher_base_class' => $app['request_matcher_class'],
260 1104
                'matcher_class' => $app['request_matcher_class'],
261 1104
                'matcher_cache_class' => $cachePrefix.'UrlMatcher',
262 1104
                'generator_cache_class' => $cachePrefix.'UrlGenerator'
263
            ];
264 1104
            $router = new EccubeRouter(
265 1104
                $app['routing.loader'],
266 1104
                $resoure,
267 1104
                $options,
268 1104
                $app['request_context'],
269 1104
                $app['logger']
270
            );
271
272 1104
            $router->setAdminPrefix($app['config']['admin_route']);
273 1104
            $router->setUserDataPrefix($app['config']['user_data_route']);
274 1104
            $router->setRequireHttps($app['config']['force_ssl']);
275
276 1104
            return $router;
277 1104
        });
278
279
        $this['eccube.router.origin'] = function ($app) {
280 1104
            $resource = __DIR__.'/Controller';
281 1104
            $cachePrefix = 'Origin';
282
283 1104
            return $app['eccube.router']($resource, $cachePrefix);
284
        };
285
286
        $this['eccube.routers.plugin'] = function ($app) {
287
            // TODO 有効なプラグインを対象とする必要がある.
288 1104
            $dirs = Finder::create()
289 1104
                ->in($app['config']['root_dir'].'/app/Plugin')
290 1104
                ->name('Controller')
291 1104
                ->directories();
292
293 1104
            $routers = [];
294 1104
            foreach ($dirs as $dir) {
295 1104
                $realPath = $dir->getRealPath();
296 1104
                $pluginCode = basename(dirname($realPath));
297 1104
                $routers[] = $app['eccube.router']($realPath, 'Plugin'.$pluginCode);
298
            }
299
300 1104
            return $routers;
301
        };
302
303
        $this['eccube.router.extend'] = function ($app) {
304
            // TODO ディレクトリ名は暫定
305 1104
            $resource = $app['config']['root_dir'].'/app/Acme/Controller';
306 1104
            $cachePrefix = 'Extend';
307
308 1104
            $router = $app['eccube.router']($resource, $cachePrefix);
309
310 1104
            return $router;
311
        };
312
313 View Code Duplication
        $this->extend('request_matcher', function ($matcher, $app) {
314 1104
            $matchers = [];
315 1104
            $matchers[] = $app['eccube.router.extend'];
316 1104
            foreach ($app['eccube.routers.plugin'] as $router) {
317 1104
                $matchers[] = $router;
318
            };
319 1104
            $matchers[] = $app['eccube.router.origin'];
320 1104
            $matchers[] = $matcher;
321
322 1104
            return new ChainUrlMatcher($matchers, $app['request_context']);
323 1104
        });
324
325 View Code Duplication
        $this->extend('url_generator', function ($generator, $app) {
326 1104
            $generators = [];
327 1104
            $generators[] = $app['eccube.router.extend'];
328 1104
            foreach ($app['eccube.routers.plugin'] as $router) {
329 1104
                $generators[] = $router;
330
            };
331 1104
            $generators[] = $app['eccube.router.origin'];
332 1104
            $generators[] = $generator;
333
334 1104
            return new ChainUrlGenerator($generators, $app['request_context']);
335 1104
        });
336
337
        // Route CollectionにEC-CUBEで定義したルーティングを追加(debug tool barに出力するため)
338
        $this->extend('routes', function ($routes, $app) {
339 1104
            $routes->addCollection($app['eccube.router.extend']->getRouteCollection());
340 1104
            foreach ($app['eccube.routers.plugin'] as $router) {
341 1104
                $routes->addCollection($router->getRouteCollection());
342
            };
343 1104
            $routes->addCollection($app['eccube.router.origin']->getRouteCollection());
344
345 1104
            return $routes;
346 1104
        });
347
348
        // init http cache
349 1104
        $this->initCacheRequest();
350
351 1104
        $this->initialized = true;
352
    }
353
354 1104
    public function initLocale()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
355
    {
356
        // locale
357 1104
        if (!empty($this['config']['locale'])) {
358 1104
            \Locale::setDefault($this['config']['locale']);
359
        };
360
361
        // timezone
362 1104
        if (!empty($this['config']['timezone'])) {
363 1104
            date_default_timezone_set($this['config']['timezone']);
364
        }
365
366 1104
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
367 1104
            'locale' => $this['config']['locale'],
368 1104
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
369
            'locale_fallbacks' => ['ja', 'en'],
370
        ));
371
        $this->extend('translator', function ($translator, \Silex\Application $app) {
372 1104
            $translator->addLoader('php', new \Symfony\Component\Translation\Loader\PhpFileLoader());
373
374 1104
            $file = __DIR__.'/Resource/locale/messages.'.$app['locale'].'.php';
375 1104
            if (file_exists($file)) {
376 1104
                $translator->addResource('php', $file, $app['locale']);
377 1104
                $translator->addResource('php', $file, $app['locale'], 'validators');
378
            }
379
380 1104
            return $translator;
381 1104
        });
382
    }
383
384 1104
    public function initSession()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
385
    {
386 1104
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
387 1104
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
388
            'session.storage.options' => array(
389 1104
                'name' => $this['config']['cookie_name'],
390 1104
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
391 1104
                'cookie_secure' => $this['config']['force_ssl'],
392 1104
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
393
                'cookie_httponly' => true,
394
                // cookie_domainは指定しない
395
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
396
            ),
397
        ));
398
399 1104
        $options = $this['config']['session_handler'];
400
401 1104
        if ($options['enabled']) {
402
            // @see http://silex.sensiolabs.org/doc/providers/session.html#custom-session-configurations
403
            $this['session.storage.handler'] = null;
404
            ini_set('session.save_handler', $options['save_handler']);
405
            ini_set('session.save_path', $options['save_path']);
406
        }
407
    }
408
409 1104
    public function initRendering()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
410
    {
411 1104
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
412 1104
            'twig.form.templates' => array('Form/form_layout.twig'),
413
        ));
414
        $this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
415 1104
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
416 1104
            $twig->addExtension(new \Twig_Extension_StringLoader());
417
418 1104
            return $twig;
419 1104
        });
420
421
        $this->before(function (Request $request, \Silex\Application $app) {
422 317
            $app['admin'] = $app['front'] = false;
423 317
            $pathinfo = rawurldecode($request->getPathInfo());
424 317
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
425 220
                $app['admin'] = true;
426
            } else {
427 97
                $app['front'] = true;
428
            }
429
430
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
431 317
            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...
432 220
                if (file_exists(__DIR__.'/../../app/template/admin')) {
433 220
                    $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...
434
                }
435 220
                $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...
436 220
                $paths[] = __DIR__.'/../../app/Plugin';
437 220
                $cacheDir =  __DIR__.'/../../app/cache/twig/admin';
438
            } else {
439
                // モバイル端末時、smartphoneディレクトリを探索パスに追加する.
440 97
                if ($app['mobile_detect.device_type'] == \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_SP) {
441
                    if (file_exists(__DIR__.'/../../app/template/smartphone')) {
442
                        $paths[] = __DIR__.'/../../app/template/smartphone';
443
                    }
444
                    $paths[] = __DIR__.'/Resource/template/smartphone';
445
                }
446
447 97
                if (file_exists($app['config']['template_realdir'])) {
448 97
                    $paths[] = $app['config']['template_realdir'];
449
                }
450 97
                $paths[] = $app['config']['template_default_realdir'];
451 97
                $paths[] = __DIR__.'/../../app/Plugin';
452 97
                $cacheDir =  __DIR__.'/../../app/cache/twig/'.$app['config']['template_code'];
453
            }
454 317
            $app['twig']->setCache($app['debug'] ? null : $cacheDir);
455 317
            $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
456
457
            // 管理画面のIP制限チェック.
458 317
            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...
459
                // IP制限チェック
460 220
                $allowHost = $app['config']['admin_allow_host'];
461 220
                if (count($allowHost) > 0) {
462
                    if (array_search($app['request_stack']->getCurrentRequest()->getClientIp(), $allowHost) === false) {
463
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
464
                    }
465
                }
466
            }
467 1104
        }, self::EARLY_EVENT);
468
469
        // twigのグローバル変数を定義.
470
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) {
471
            // 未ログイン時にマイページや管理画面以下にアクセスするとSubRequestで実行されるため,
472
            // $event->isMasterRequest()ではなく、グローバル変数が初期化済かどうかの判定を行う
473 315
            if (isset($this['twig_global_initialized']) && $this['twig_global_initialized'] === true) {
474 45
                return;
475
            }
476
            // ショップ基本情報
477 315
            $BaseInfo = $this['eccube.repository.base_info']->get();
478 315
            $this['twig']->addGlobal('BaseInfo', $BaseInfo);
479
480 315
            if ($this->isAdminRequest()) {
481
                // 管理画面
482
                // 管理画面メニュー
483 220
                $menus = array('', '', '');
484 220
                $this['twig']->addGlobal('menus', $menus);
485
486 220
                $Member = $this->user();
487 220
                if (is_object($Member)) {
488
                    // ログインしていれば管理者のロールを取得
489 217
                    $AuthorityRoles = $this['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
490
491 217
                    $roles = array();
492 217
                    $request = $event->getRequest();
493 217
                    foreach ($AuthorityRoles as $AuthorityRole) {
494
                        // 管理画面でメニュー制御するため相対パス全てをセット
495 3
                        $roles[] = $request->getBaseUrl().'/'.$this['config']['admin_route'].$AuthorityRole->getDenyUrl();
496
                    }
497
498 220
                    $this['twig']->addGlobal('AuthorityRoles', $roles);
499
                }
500
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
501
            } else {
502
                // フロント画面
503 95
                $request = $event->getRequest();
504 95
                $route = $request->attributes->get('_route');
505
506
                // ユーザ作成画面
507 95
                if ($route === 'user_data') {
508 2
                    $params = $request->attributes->get('_route_params');
509 2
                    $route = $params['route'];
510
                    // プレビュー画面
511 93
                } elseif ($request->get('preview')) {
512
                    $route = 'preview';
513
                }
514
515
                try {
516 95
                    $device_type_id = $this['mobile_detect.device_type'];
517
518
                    // TODO デバッグ用
519 95
                    if ($request->query->has('device_type_id')) {
520
                        $device_type_id = $request->get('device_type_id', \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
521
                    }
522
523 95
                    $DeviceType = $this['eccube.repository.master.device_type']
524 95
                        ->find($device_type_id);
525 95
                    $qb = $this['eccube.repository.page_layout']->createQueryBuilder('p');
526 95
                    $PageLayout = $qb->select('p, pll,l, bp, b')
527 95
                        ->leftJoin('p.PageLayoutLayouts', 'pll')
528 95
                        ->leftJoin('pll.Layout', 'l')
529 95
                        ->leftJoin('l.BlockPositions', 'bp')
530 95
                        ->leftJoin('bp.Block', 'b')
531 95
                        ->where('p.url = :route')
532 95
                        ->andWhere('l.DeviceType = :DeviceType')
533 95
                        ->orderBy('bp.block_row', 'ASC')
534 95
                        ->setParameter('route', $route)
535 95
                        ->setParameter('DeviceType', $DeviceType)
536 95
                        ->getQuery()
537 95
                        ->getSingleResult();
538 33
                } catch (\Doctrine\ORM\NoResultException $e) {
539 33
                    $PageLayout = $this['eccube.repository.page_layout']->newPageLayout($DeviceType);
0 ignored issues
show
Bug introduced by
The variable $DeviceType does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

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