Failed Conditions
Pull Request — experimental/3.1 (#2494)
by chihiro
49:51 queued 21:25
created

Application::parseConfig()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 5

Importance

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