Completed
Pull Request — master (#2123)
by Ryo
63:35
created

Application::initConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 15
nc 1
nop 0
dl 0
loc 20
ccs 15
cts 15
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
namespace Eccube;
25
26
use Binfo\Silex\MobileDetectServiceProvider;
27
use Eccube\Application\ApplicationTrait;
28
use Eccube\Common\Constant;
29
use Eccube\Doctrine\ORM\Mapping\Driver\YamlDriver;
30
use Eccube\EventListener\TransactionListener;
31
use Symfony\Component\EventDispatcher\EventDispatcher;
32
use Symfony\Component\Finder\Finder;
33
use Symfony\Component\HttpFoundation\Request;
34
use Symfony\Component\HttpFoundation\Response;
35
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
36
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
37
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
38
use Symfony\Component\HttpKernel\KernelEvents;
39
use Symfony\Component\Yaml\Yaml;
40
41
class Application extends ApplicationTrait
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
42
{
43
    protected static $instance;
44
45
    protected $initialized = false;
46
    protected $initializedPlugin = false;
47
    protected $testMode = false;
48
49 1193
    public static function getInstance(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
50
    {
51 1193
        if (!is_object(self::$instance)) {
52 1186
            self::$instance = new Application($values);
53
        }
54
55 1193
        return self::$instance;
56
    }
57
58 1187
    public static function clearInstance()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
59
    {
60 1187
        self::$instance = null;
61
    }
62
63
    final public function __clone()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
64
    {
65
        throw new \Exception('Clone is not allowed against '.get_class($this));
66
    }
67
68 1191
    public function __construct(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
69
    {
70 1191
        parent::__construct($values);
71
72 1191
        if (is_null(self::$instance)) {
73 1187
            self::$instance = $this;
74
        }
75
76
        // load config
77 1191
        $this->initConfig();
78
79
        // init monolog
80 1191
        $this->initLogger();
81
    }
82
83
    /**
84
     * Application::runが実行されているか親クラスのプロパティから判定
85
     *
86
     * @return bool
87
     */
88 1192
    public function isBooted()
89
    {
90 1192
        return $this->booted;
91
    }
92
93 1191
    public function initConfig()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
94
    {
95
        // load config
96 1191
        $app = $this;
97
        $this['config'] = $this->share(function() use ($app) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
98 1191
            $configAll = array();
99 1191
            $app->parseConfig('constant', $configAll)
100 1191
                ->parseConfig('path', $configAll)
101 1191
                ->parseConfig('config', $configAll)
102 1191
                ->parseConfig('database', $configAll)
103 1191
                ->parseConfig('mail', $configAll)
104 1191
                ->parseConfig('log', $configAll)
105 1191
                ->parseConfig('nav', $configAll, true)
106 1191
                ->parseConfig('doctrine_cache', $configAll)
107 1191
                ->parseConfig('http_cache', $configAll)
108 1191
                ->parseConfig('session_handler', $configAll);
109
110 1191
            return $configAll;
111 1191
        });
112
    }
113
114 1193
    public function initLogger()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
115
    {
116 1193
        $app = $this;
117 1193
        $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...
118
    }
119
120 1190
    public function initialize()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
121
    {
122 1190
        if ($this->initialized) {
123 4
            return;
124
        }
125
126
        // init locale
127 1187
        $this->initLocale();
128
129
        // init session
130 1187
        if (!$this->isSessionStarted()) {
131 1187
            $this->initSession();
132
        }
133
134
        // init twig
135 1187
        $this->initRendering();
136
137
        // init provider
138 1187
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
139 1187
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
140
        ));
141 1187
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
142 1187
        $this->register(new \Silex\Provider\UrlGeneratorServiceProvider());
143 1187
        $this->register(new \Silex\Provider\FormServiceProvider());
144 1187
        $this->register(new \Silex\Provider\SerializerServiceProvider());
145 1187
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
146 1187
        $this->register(new MobileDetectServiceProvider());
147
148 1187
        $app = $this;
149
        $this->error(function (\Exception $e, $code) use ($app) {
150 20
            if ($app['debug']) {
151 20
                return;
152
            }
153
154
            switch ($code) {
155
                case 403:
156
                    $title = 'アクセスできません。';
157
                    $message = 'お探しのページはアクセスができない状況にあるか、移動もしくは削除された可能性があります。';
158
                    break;
159
                case 404:
160
                    $title = 'ページがみつかりません。';
161
                    $message = 'URLに間違いがないかご確認ください。';
162
                    break;
163
                default:
164
                    $title = 'システムエラーが発生しました。';
165
                    $message = '大変お手数ですが、サイト管理者までご連絡ください。';
166
                    break;
167
            }
168
169
            return $app->render('error.twig', array(
170
                'error_title' => $title,
171
                'error_message' => $message,
172
            ));
173 1187
        });
174
175
        // init mailer
176 1187
        $this->initMailer();
177
178
        // init doctrine orm
179 1187
        $this->initDoctrine();
180
181
        // Set up the DBAL connection now to check for a proper connection to the database.
182 1187
        $this->checkDatabaseConnection();
183
184
        // init security
185 1187
        $this->initSecurity();
186
187
        // init proxy
188 1187
        $this->initProxy();
189
190
        // init ec-cube service provider
191 1187
        $this->register(new ServiceProvider\EccubeServiceProvider());
192
193
        // mount controllers
194 1187
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
195 1187
        $this->mount('', new ControllerProvider\FrontControllerProvider());
196 1187
        $this->mount('/'.trim($this['config']['admin_route'], '/').'/', new ControllerProvider\AdminControllerProvider());
197 1187
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
198
199
        // add transaction listener
200 1187
        $this['dispatcher']->addSubscriber(new TransactionListener($this));
201
202
        // init http cache
203 1187
        $this->initCacheRequest();
204
205 1187
        $this->initialized = true;
206
    }
207
208 1187
    public function initLocale()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
209
    {
210
211
        // timezone
212 1187
        if (!empty($this['config']['timezone'])) {
213 1187
            date_default_timezone_set($this['config']['timezone']);
214
        }
215
216 1187
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
217 1187
            'locale' => $this['config']['locale'],
218 1187
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
219
        ));
220
        $this['translator'] = $this->share($this->extend('translator', function ($translator, \Silex\Application $app) {
221 830
            $translator->addLoader('yaml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
222
223 830
            $file = __DIR__.'/Resource/locale/validator.'.$app['locale'].'.yml';
224 830
            if (file_exists($file)) {
225 830
                $translator->addResource('yaml', $file, $app['locale'], 'validators');
226
            }
227
228 830
            $file = __DIR__.'/Resource/locale/message.'.$app['locale'].'.yml';
229 830
            if (file_exists($file)) {
230 830
                $translator->addResource('yaml', $file, $app['locale']);
231
            }
232
233 830
            return $translator;
234 1187
        }));
235
    }
236
237 1187
    public function initSession()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
238
    {
239 1187
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
240 1187
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
241
            'session.storage.options' => array(
242 1187
                'name' => $this['config']['cookie_name'],
243 1187
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
244 1187
                'cookie_secure' => $this['config']['force_ssl'],
245 1187
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
246
                'cookie_httponly' => true,
247
                // cookie_domainは指定しない
248
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
249
            ),
250
        ));
251
252 1187
        $options = $this['config']['session_handler'];
253
254 1187
        if ($options['enabled']) {
255
            // @see http://silex.sensiolabs.org/doc/providers/session.html#custom-session-configurations
256
            $this['session.storage.handler'] = null;
257
            ini_set('session.save_handler', $options['save_handler']);
258
            ini_set('session.save_path', $options['save_path']);
259
        }
260
    }
261
262 1187
    public function initRendering()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
263
    {
264 1187
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
265 1187
            'twig.form.templates' => array('Form/form_layout.twig'),
266
        ));
267
        $this['twig'] = $this->share($this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
268 583
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
269 583
            $twig->addExtension(new \Twig_Extension_StringLoader());
270
271 583
            return $twig;
272 1187
        }));
273
274
        $this->before(function (Request $request, \Silex\Application $app) {
275 572
            $app['admin'] = false;
276 572
            $app['front'] = false;
277 572
            $pathinfo = rawurldecode($request->getPathInfo());
278 572
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
279 312
                $app['admin'] = true;
280
            } else {
281 262
                $app['front'] = true;
282
            }
283
284
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
285
            $app['twig'] = $app->share($app->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
286 570
                $paths = array();
287
288
                // 互換性がないのでprofiler とproduction 時のcacheを分離する
289 570
                if (isset($app['profiler'])) {
290
                    $cacheBaseDir = __DIR__.'/../../app/cache/twig/profiler/';
291
                } else {
292 570
                    $cacheBaseDir = __DIR__.'/../../app/cache/twig/production/';
293
                }
294
295 570
                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\Application\ApplicationTrait, 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...
296 312
                    if (file_exists(__DIR__.'/../../app/template/admin')) {
297 312
                        $paths[] = __DIR__.'/../../app/template/admin';
298
                    }
299 312
                    $paths[] = $app['config']['template_admin_realdir'];
300 312
                    $paths[] = __DIR__.'/../../app/Plugin';
301 312
                    $cache = $cacheBaseDir.'admin';
302
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
303
                } else {
304 260
                    if (file_exists($app['config']['template_realdir'])) {
305 260
                        $paths[] = $app['config']['template_realdir'];
306
                    }
307 260
                    $paths[] = $app['config']['template_default_realdir'];
308 260
                    $paths[] = __DIR__.'/../../app/Plugin';
309 260
                    $cache = $cacheBaseDir.$app['config']['template_code'];
310 260
                    $app['front'] = true;
311
                }
312 570
                $twig->setCache($cache);
313 570
                $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
314
315 570
                return $twig;
316 572
            }));
317
318
            // 管理画面のIP制限チェック.
319 572
            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\Application\ApplicationTrait, 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...
320
                // IP制限チェック
321 312
                $allowHost = $app['config']['admin_allow_host'];
322 312
                if (count($allowHost) > 0) {
323
                    if (array_search($app['request']->getClientIp(), $allowHost) === false) {
324
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
325
                    }
326
                }
327
            }
328 1187
        }, self::EARLY_EVENT);
329
330
        // twigのグローバル変数を定義.
331 1187
        $app = $this;
332
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {
333
            // 未ログイン時にマイページや管理画面以下にアクセスするとSubRequestで実行されるため,
334
            // $event->isMasterRequest()ではなく、グローバル変数が初期化済かどうかの判定を行う
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
335 570
            if (isset($app['twig_global_initialized']) && $app['twig_global_initialized'] === true) {
336 211
                return;
337
            }
338
            // ショップ基本情報
339 570
            $BaseInfo = $app['eccube.repository.base_info']->get();
340 570
            $app['twig']->addGlobal('BaseInfo', $BaseInfo);
341
342 570
            if ($app->isAdminRequest()) {
343
                // 管理画面
344
                // 管理画面メニュー
345 312
                $menus = array('', '', '');
346 312
                $app['twig']->addGlobal('menus', $menus);
347
348 312
                $Member = $app->user();
349 312
                if (is_object($Member)) {
350
                    // ログインしていれば管理者のロールを取得
351 306
                    $AuthorityRoles = $app['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
352
353 306
                    $roles = array();
354 306
                    foreach ($AuthorityRoles as $AuthorityRole) {
355
                        // 管理画面でメニュー制御するため相対パス全てをセット
356 306
                        $roles[] = $app['request']->getBaseUrl().'/'.$app['config']['admin_route'].$AuthorityRole->getDenyUrl();
357
                    }
358
359 312
                    $app['twig']->addGlobal('AuthorityRoles', $roles);
360
                }
361
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
362
            } else {
363
                // フロント画面
364 258
                $request = $event->getRequest();
365 258
                $route = $request->attributes->get('_route');
366
367
                // ユーザ作成画面
368 258
                if ($route === 'user_data') {
369 2
                    $params = $request->attributes->get('_route_params');
370 2
                    $route = $params['route'];
371
                    // プレビュー画面
372 256
                } elseif ($request->get('preview')) {
373
                    $route = 'preview';
374
                }
375
376
                try {
377 258
                    $DeviceType = $app['eccube.repository.master.device_type']
378 258
                        ->find(\Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
379 258
                    $PageLayout = $app['eccube.repository.page_layout']->getByUrl($DeviceType, $route);
380 145
                } catch (\Doctrine\ORM\NoResultException $e) {
381 145
                    $PageLayout = $app['eccube.repository.page_layout']->newPageLayout($DeviceType);
382
                }
383
384 258
                $app['twig']->addGlobal('PageLayout', $PageLayout);
385 258
                $app['twig']->addGlobal('title', $PageLayout->getName());
386
            }
387
388 570
            $app['twig_global_initialized'] = true;
389 1187
        });
390
    }
391
392 1187
    public function initMailer()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
393
    {
394
395
        // メール送信時の文字エンコード指定(デフォルトはUTF-8)
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
396 1187
        if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
397 1187
            if ($this['config']['mail']['charset_iso_2022_jp'] === true) {
398
                \Swift::init(function () {
399
                    \Swift_DependencyContainer::getInstance()
400
                        ->register('mime.qpheaderencoder')
401
                        ->asAliasOf('mime.base64headerencoder');
402
                    \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
403
                });
404
            }
405
        }
406
407 1187
        $this->register(new \Silex\Provider\SwiftmailerServiceProvider());
408 1187
        $this['swiftmailer.options'] = $this['config']['mail'];
409
410 1187
        if (isset($this['config']['mail']['spool']) && is_bool($this['config']['mail']['spool'])) {
411
            $this['swiftmailer.use_spool'] = $this['config']['mail']['spool'];
412
        }
413
        // デフォルトはsmtpを使用
414 1187
        $transport = $this['config']['mail']['transport'];
415 1187
        if ($transport == 'sendmail') {
416
            $this['swiftmailer.transport'] = \Swift_SendmailTransport::newInstance();
417 1187
        } elseif ($transport == 'mail') {
418
            $this['swiftmailer.transport'] = \Swift_MailTransport::newInstance();
419
        }
420
    }
421
422 1187
    public function initDoctrine()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
423
    {
424 1187
        $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...
425
            'dbs.options' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
426 1187
                'default' => $this['config']['database']
427
            )));
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
428 1187
        $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Silex\Provider\DoctrineOrmManagerRegistryProvider());
429
430
        // プラグインのmetadata定義を合わせて行う.
431 1187
        $pluginConfigs = $this->getPluginConfigAll();
432 1187
        $ormMappings = array();
433 1187
        $ormMappings[] = array(
434
            'type' => 'yml',
435
            'namespace' => 'Eccube\Entity',
436
            'path' => array(
437
                __DIR__.'/Resource/doctrine',
438
                __DIR__.'/Resource/doctrine/master',
439
            ),
440
        );
441
442 1187
        foreach ($pluginConfigs as $code) {
443 140
            $config = $code['config'];
444
            // Doctrine Extend
445 140
            if (isset($config['orm.path']) && is_array($config['orm.path'])) {
446
                $paths = array();
447
                foreach ($config['orm.path'] as $path) {
448
                    $paths[] = $this['config']['plugin_realdir'].'/'.$config['code'].$path;
449
                }
450
                $ormMappings[] = array(
451
                    'type' => 'yml',
452
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
453 1187
                    'path' => $paths,
454
                );
455
            }
456
        }
457
458
        $options = array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
459 1187
            'mappings' => $ormMappings
460
        );
461
462 1187
        if (!$this['debug']) {
463 1
            $cacheDrivers = array();
464 1
            if (array_key_exists('doctrine_cache', $this['config'])) {
465 1
                $cacheDrivers = $this['config']['doctrine_cache'];
466
            }
467
468 1
            if (array_key_exists('metadata_cache', $cacheDrivers)) {
469 1
                $options['metadata_cache'] = $cacheDrivers['metadata_cache'];
470
            }
471 1
            if (array_key_exists('query_cache', $cacheDrivers)) {
472 1
                $options['query_cache'] = $cacheDrivers['query_cache'];
473
            }
474 1
            if (array_key_exists('result_cache', $cacheDrivers)) {
475 1
                $options['result_cache'] = $cacheDrivers['result_cache'];
476
            }
477 1
            if (array_key_exists('hydration_cache', $cacheDrivers)) {
478 1
                $options['hydration_cache'] = $cacheDrivers['hydration_cache'];
479
            }
480
        }
481
482 1187
        $this->register(new \Dflydev\Silex\Provider\DoctrineOrm\DoctrineOrmServiceProvider(), array(
483 1187
            'orm.proxies_dir' => __DIR__.'/../../app/cache/doctrine/proxies',
484 1187
            'orm.em.options' => $options,
485
            'orm.custom.functions.string' => array(
486
                'NORMALIZE' => 'Eccube\Doctrine\ORM\Query\Normalize',
487
            ),
488
            'orm.custom.functions.numeric' => array(
489
                'EXTRACT' => 'Eccube\Doctrine\ORM\Query\Extract',
490
            ),
491
        ));
492
493
        /**
494
         * YamlDriverのPHP7対応. Doctrine2.4で修正されれば不要.
495
         * @see https://github.com/EC-CUBE/ec-cube/issues/1338
496
         */
497 1187
        $config = $this['orm.em']->getConfiguration();
498
        /** @var $driver \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain */
499 1187
        $chain = $config->getMetadataDriverImpl();
500
        // $ormMappingsの1要素ごとにDriverが生成されている.
501 1187
        $drivers = $chain->getDrivers();
502 1187
        foreach ($drivers as $namespace => $oldDriver) {
503
            /** @var $newDriver \Eccube\Doctrine\ORM\Mapping\Driver\YamlDriver */
504 1187
            $newDriver = new YamlDriver($oldDriver->getLocator());
505
            // 修正したDriverに差し替える. メソッド名はaddだけど実際はsetしてる.
506 1187
            $chain->addDriver($newDriver, $namespace);
507
        }
508
    }
509
510 1189
    public function initSecurity()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
511
    {
512 1187
        $this->register(new \Silex\Provider\SecurityServiceProvider());
513 1187
        $this->register(new \Silex\Provider\RememberMeServiceProvider());
514
515 1187
        $this['security.firewalls'] = array(
516
            'admin' => array(
517 1187
                'pattern' => "^/{$this['config']['admin_route']}/",
518
                'form' => array(
519 1187
                    'login_path' => "/{$this['config']['admin_route']}/login",
520 1187
                    'check_path' => "/{$this['config']['admin_route']}/login_check",
521 1187
                    'username_parameter' => 'login_id',
522 1187
                    'password_parameter' => 'password',
523
                    'with_csrf' => true,
524
                    'use_forward' => true,
525
                ),
526
                'logout' => array(
527 1187
                    'logout_path' => "/{$this['config']['admin_route']}/logout",
528 1187
                    'target_url' => "/{$this['config']['admin_route']}/",
529
                ),
530 1187
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Member'),
531
                'anonymous' => true,
532 1187
            ),
533
            'customer' => array(
534 1187
                'pattern' => '^/',
535
                'form' => array(
536
                    'login_path' => '/mypage/login',
537
                    'check_path' => '/login_check',
538
                    'username_parameter' => 'login_email',
539
                    'password_parameter' => 'login_pass',
540
                    'with_csrf' => true,
541
                    'use_forward' => true,
542
                ),
543
                'logout' => array(
544
                    'logout_path' => '/logout',
545
                    'target_url' => '/',
546
                ),
547
                'remember_me' => array(
548 1187
                    'key' => sha1($this['config']['auth_magic']),
549 1187
                    'name' => $this['config']['cookie_name'].'_rememberme',
550
                    // lifetimeはデフォルトの1年間にする
551
                    // 'lifetime' => $this['config']['cookie_lifetime'],
0 ignored issues
show
Unused Code Comprehensibility introduced by
77% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
552 1187
                    'path' => $this['config']['root_urlpath'] ?: '/',
553 1187
                    'secure' => $this['config']['force_ssl'],
554
                    'httponly' => true,
555
                    'always_remember_me' => false,
556 1187
                    'remember_me_parameter' => 'login_memory',
557
                ),
558 1187
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Customer'),
559
                'anonymous' => true,
560
            ),
561
        );
562
563 1187
        $channel = null;
564
        // 強制SSL
565 1187
        if ($this['config']['force_ssl'] == \Eccube\Common\Constant::ENABLED) {
566
            $channel = "https";
567
        }
568
569 1187
        $this['security.access_rules'] = array(
570 1187
            array("^/{$this['config']['admin_route']}/login", 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
571 1187
            array("^/{$this['config']['admin_route']}/", 'ROLE_ADMIN', $channel),
572 1187
            array('^/mypage/login', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
573 1187
            array('^/mypage/withdraw_complete', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
574 1187
            array('^/mypage/change', 'IS_AUTHENTICATED_FULLY', $channel),
575 1187
            array('^/mypage', 'ROLE_USER', $channel),
576
        );
577
578
        $this['eccube.password_encoder'] = $this->share(function ($app) {
579 1187
            return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
580 1187
        });
581
        $this['security.encoder_factory'] = $this->share(function ($app) {
582 1187
            return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
583 1187
                'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
584 1187
                'Eccube\Entity\Member' => $app['eccube.password_encoder'],
585
            ));
586 1187
        });
587
        $this['eccube.event_listner.security'] = $this->share(function ($app) {
588 1187
            return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
589 1187
        });
590
        $this['user'] = function ($app) {
591 1189
            $token = $app['security']->getToken();
592
593 1189
            return ($token !== null) ? $token->getUser() : null;
594
        };
595
596
        // ログイン時のイベントを設定.
597 1187
        $this['dispatcher']->addListener(\Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN, array($this['eccube.event_listner.security'], 'onInteractiveLogin'));
598
599
        // Voterの設定
600 1187
        $app = $this;
601
        $this['authority_voter'] = $this->share(function ($app) {
602 1187
            return new \Eccube\Security\Voter\AuthorityVoter($app);
603 1187
        });
604
605
        $app['security.voters'] = $app->extend('security.voters', function ($voters) use ($app) {
606 1187
            $voters[] = $app['authority_voter'];
607
608 1187
            return $voters;
609 1187
        });
610
611
        $this['security.access_manager'] = $this->share(function ($app) {
612 1187
            return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
613 1187
        });
614
615
    }
616
617
    /**
618
     * ロードバランサー、プロキシサーバの設定を行う
619
     */
620 1187
    public function initProxy()
621
    {
622 1187
        $config = $this['config'];
623 1187
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
624
            $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($config) {
625
                // サブリクエストのREMOTE_ADDRも動的に設定を行う必要があるため、KernelEvents::REQUESTを使用する
626
                Request::setTrustedProxies(array_merge(array($event->getRequest()->server->get('REMOTE_ADDR')), $config['trusted_proxies']));
627
            }, self::EARLY_EVENT);
628 1187 View Code Duplication
        } elseif (isset($config['trusted_proxies']) && !empty($config['trusted_proxies'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
629
            Request::setTrustedProxies($config['trusted_proxies']);
630
        }
631
    }
632
633 1187
    public function initializePlugin()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
634
    {
635 1187
        if ($this->initializedPlugin) {
636
            return;
637
        }
638
639
        // setup event dispatcher
640 1187
        $this->initPluginEventDispatcher();
641
642
        // load plugin
643 1187
        $this->loadPlugin();
644
645 1187
        $this->initializedPlugin = true;
646
    }
647
648 1187
    public function initPluginEventDispatcher()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
649
    {
650
        // EventDispatcher
651
        $this['eccube.event.dispatcher'] = $this->share(function () {
652 585
            return new EventDispatcher();
653 1187
        });
654
655 1187
        $app = $this;
656
657
        // hook point
658
        $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($app) {
659 572
            if (!$event->isMasterRequest()) {
660 81
                return;
661
            }
662 572
            $hookpoint = 'eccube.event.app.before';
663 572
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
664 1187
        }, self::EARLY_EVENT);
665
666 View Code Duplication
        $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($app) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
667 571
            if (!$event->isMasterRequest()) {
668 81
                return;
669
            }
670 569
            $route = $event->getRequest()->attributes->get('_route');
671 569
            $hookpoint = "eccube.event.controller.$route.before";
672 569
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
673 1187
        });
674
675 View Code Duplication
        $this->on(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($app) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
676 558
            if (!$event->isMasterRequest()) {
677 81
                return;
678
            }
679 558
            $route = $event->getRequest()->attributes->get('_route');
680 558
            $hookpoint = "eccube.event.controller.$route.after";
681 558
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
682 1187
        });
683
684
        $this->on(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($app) {
685 558
            if (!$event->isMasterRequest()) {
686 81
                return;
687
            }
688 558
            $hookpoint = 'eccube.event.app.after';
689 558
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
690 1187
        }, self::LATE_EVENT);
691
692
        $this->on(KernelEvents::TERMINATE, function (PostResponseEvent $event) use ($app) {
693 558
            $route = $event->getRequest()->attributes->get('_route');
694 558
            $hookpoint = "eccube.event.controller.$route.finish";
695 558
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
696 1187
        });
697
698
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
699 558
            if (!$event->isMasterRequest()) {
700 81
                return;
701
            }
702 558
            $route = $event->getRequest()->attributes->get('_route');
703 558
            $app['eccube.event.dispatcher']->dispatch('eccube.event.render.'.$route.'.before', $event);
704 1187
        });
705
706
        // Request Event
707 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::REQUEST, function (\Symfony\Component\HttpKernel\Event\GetResponseEvent $event) use ($app) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
708
709 571
            if (!$event->isMasterRequest()) {
710 81
                return;
711
            }
712
713 571
            $route = $event->getRequest()->attributes->get('_route');
714
715 571
            if (is_null($route)) {
716
                return;
717
            }
718
719 571
            $app['monolog']->debug('KernelEvents::REQUEST '.$route);
720
721
            // 全体
722 571
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.request', $event);
723
724 571
            if (strpos($route, 'admin') === 0) {
725
                // 管理画面
726 312
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.request', $event);
727
            } else {
728
                // フロント画面
729 261
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.request', $event);
730
            }
731
732
            // ルーティング単位
733 571
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.request", $event);
734
735 1187
        }, 30); // Routing(32)が解決しし, 認証判定(8)が実行される前のタイミング.
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
736
737
        // Controller Event
738 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
739
740 570
            if (!$event->isMasterRequest()) {
741 81
                return;
742
            }
743
744 568
            $route = $event->getRequest()->attributes->get('_route');
745
746 568
            if (is_null($route)) {
747
                return;
748
            }
749
750 568
            $app['monolog']->debug('KernelEvents::CONTROLLER '.$route);
751
752
            // 全体
753 568
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.controller', $event);
754
755 568
            if (strpos($route, 'admin') === 0) {
756
                // 管理画面
757 310
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.controller', $event);
758
            } else {
759
                // フロント画面
760 260
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.controller', $event);
761
            }
762
763
            // ルーティング単位
764 568
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.controller", $event);
765 1187
        });
766
767
        // Response Event
768 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
769 558
            if (!$event->isMasterRequest()) {
770 81
                return;
771
            }
772
773 558
            $route = $event->getRequest()->attributes->get('_route');
774
775 558
            if (is_null($route)) {
776 1
                return;
777
            }
778
779 557
            $app['monolog']->debug('KernelEvents::RESPONSE '.$route);
780
781
            // ルーティング単位
782 557
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.response", $event);
783
784 557
            if (strpos($route, 'admin') === 0) {
785
                // 管理画面
786 305
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.response', $event);
787
            } else {
788
                // フロント画面
789 254
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.response', $event);
790
            }
791
792
            // 全体
793 557
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.response', $event);
794 1187
        });
795
796
        // Exception Event
797 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::EXCEPTION, function (\Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event) use ($app) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
798
799 22
            if (!$event->isMasterRequest()) {
800
                return;
801
            }
802
803 22
            $route = $event->getRequest()->attributes->get('_route');
804
805 22
            if (is_null($route)) {
806
                return;
807
            }
808
809 22
            $app['monolog']->debug('KernelEvents::EXCEPTION '.$route);
810
811
            // ルーティング単位
812 22
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.exception", $event);
813
814 22
            if (strpos($route, 'admin') === 0) {
815
                // 管理画面
816 9
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.exception', $event);
817
            } else {
818
                // フロント画面
819 13
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.exception', $event);
820
            }
821
822
            // 全体
823 22
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.exception', $event);
824 1187
        });
825
826
        // Terminate Event
827 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::TERMINATE, function (\Symfony\Component\HttpKernel\Event\PostResponseEvent $event) use ($app) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
828
829 558
            $route = $event->getRequest()->attributes->get('_route');
830
831 558
            if (is_null($route)) {
832 1
                return;
833
            }
834
835 557
            $app['monolog']->debug('KernelEvents::TERMINATE '.$route);
836
837
            // ルーティング単位
838 557
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.terminate", $event);
839
840 557
            if (strpos($route, 'admin') === 0) {
841
                // 管理画面
842 305
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.terminate', $event);
843
            } else {
844
                // フロント画面
845 254
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.terminate', $event);
846
            }
847
848
            // 全体
849 557
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.terminate', $event);
850 1187
        });
851
    }
852
853 1187
    public function loadPlugin()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
854
    {
855
        // プラグインディレクトリを探索.
856 1187
        $basePath = $this['config']['plugin_realdir'];
857 1187
        $pluginConfigs = $this->getPluginConfigAll();
858
859
        // ハンドラ優先順位をdbから持ってきてハッシュテーブルを作成
860 1187
        $priorities = array();
861 1187
        $handlers = $this['orm.em']
862 1187
            ->getRepository('Eccube\Entity\PluginEventHandler')
863 1187
            ->getHandlers();
864
865 1187
        foreach ($handlers as $handler) {
866 1
            if ($handler->getPlugin()->getEnable() && !$handler->getPlugin()->getDelFlg()) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
867
868
                $priority = $handler->getPriority();
869
            } else {
870
                // Pluginがdisable、削除済みの場合、EventHandlerのPriorityを全て0とみなす
871 1
                $priority = \Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_DISABLED;
872
            }
873 1187
            $priorities[$handler->getPlugin()->getClassName()][$handler->getEvent()][$handler->getHandler()] = $priority;
874
        }
875
876
        // プラグインをロードする.
877
        // config.yml/event.ymlの定義に沿ってインスタンスの生成を行い, イベント設定を行う.
878 1187
        foreach ($pluginConfigs as $code => $pluginConfig) {
879
            // 正しい形式の pluginConfig のみ読み込む
880 142
            $path = $basePath.'/'.$code;
881
            try {
882 142
                $this['eccube.service.plugin']->checkPluginArchiveContent($path, $pluginConfig['config']);
883
            } catch (\Eccube\Exception\PluginException $e) {
884
                $this['monolog']->warning("Configuration file config.yml for plugin {$code} not found or is invalid. Skipping loading.", array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
885
                    'path' => $path,
886
                    'original-message' => $e->getMessage()
887
                ));
888
                continue;
889
            }
890 142
            $config = $pluginConfig['config'];
891
892 142
            $plugin = $this['orm.em']
893 142
                ->getRepository('Eccube\Entity\Plugin')
894 142
                ->findOneBy(array('code' => $config['code']));
895
896
            // const
897 142
            if (isset($config['const'])) {
898
                $this['config'] = $this->share($this->extend('config', function ($eccubeConfig) use ($config) {
899 2
                    $eccubeConfig[$config['code']] = array(
900 2
                        'const' => $config['const'],
901
                    );
902
903 2
                    return $eccubeConfig;
904 2
                }));
905
            }
906
907 142
            if ($plugin && $plugin->getEnable() == Constant::DISABLED) {
908
                // プラグインが無効化されていれば読み込まない
909 2
                continue;
910
            }
911
912
            // Type: Event
913 140
            if (isset($config['event'])) {
914 140
                $class = '\\Plugin\\'.$config['code'].'\\'.$config['event'];
915 140
                $eventExists = true;
916
917 140 View Code Duplication
                if (!class_exists($class)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
918
                    $this['monolog']->warning("Event class for plugin {$code} not exists.", array(
919
                        'class' => $class,
920
                    ));
921
                    $eventExists = false;
922
                }
923
924 140
                if ($eventExists && isset($config['event'])) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
925
926 140
                    $subscriber = new $class($this);
927
928 140
                    foreach ($pluginConfig['event'] as $event => $handlers) {
929 140
                        foreach ($handlers as $handler) {
930 140
                            if (!isset($priorities[$config['event']][$event][$handler[0]])) { // ハンドラテーブルに登録されていない(ソースにしか記述されていない)ハンドラは一番後ろにする
931 140
                                $priority = \Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_LATEST;
932
                            } else {
933
                                $priority = $priorities[$config['event']][$event][$handler[0]];
934
                            }
935
                            // 優先度が0のプラグインは登録しない
936 140
                            if (\Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_DISABLED != $priority) {
937 140
                                $this['eccube.event.dispatcher']->addListener($event, array($subscriber, $handler[0]), $priority);
938
                            }
939
                        }
940
                    }
941
                }
942
            }
943
            // Type: ServiceProvider
944 140
            if (isset($config['service'])) {
945
                foreach ($config['service'] as $service) {
946
                    $class = '\\Plugin\\'.$config['code'].'\\ServiceProvider\\'.$service;
947 View Code Duplication
                    if (!class_exists($class)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
948
                        $this['monolog']->warning("Service provider class for plugin {$code} not exists.", array(
949
                            'class' => $class,
950
                        ));
951
                        continue;
952
                    }
953 1187
                    $this->register(new $class($this));
954
                }
955
            }
956
        }
957
    }
958
959
    /**
960
     * PHPUnit を実行中かどうかを設定する.
961
     *
962
     * @param boolean $testMode PHPUnit を実行中の場合 true
963
     */
964 1177
    public function setTestMode($testMode)
965
    {
966 1177
        $this->testMode = $testMode;
967
    }
968
969
    /**
970
     * PHPUnit を実行中かどうか.
971
     *
972
     * @return boolean PHPUnit を実行中の場合 true
973
     */
974 572
    public function isTestMode()
975
    {
976 572
        return $this->testMode;
977
    }
978
979
    /**
980
     *
981
     * データベースの接続を確認
982
     * 成功 : trueを返却
983
     * 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
984
     * 備考 : app['debug']がtrueの際は処理を行わない
985
     *
986
     * @return boolean true
987
     *
988
     */
989 1187
    protected function checkDatabaseConnection()
990
    {
991 1187
        if ($this['debug']) {
992 1186
            return;
993
        }
994
        try {
995 1
            $this['db']->connect();
996
        } catch (\Doctrine\DBAL\DBALException $e) {
997
            $this['monolog']->error($e->getMessage());
998
            $this['twig.path'] = array(__DIR__.'/Resource/template/exception');
999
            $html = $this['twig']->render('error.twig', array(
1000
                'error_title' => 'データーベース接続エラー',
1001
                'error_message' => 'データーベースを確認してください',
1002
            ));
1003
            $response = new Response();
1004
            $response->setContent($html);
1005
            $response->setStatusCode('500');
1006
            $response->headers->set('Content-Type', 'text/html');
1007
            $response->send();
1008
            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...
1009
        }
1010
1011 1
        return true;
1012
    }
1013
1014
    /**
1015
     * Config ファイルをパースし、連想配列を返します.
1016
     *
1017
     * $config_name.yml ファイルをパースし、連想配列を返します.
1018
     * $config_name.php が存在する場合は、 PHP ファイルに記述された連想配列を使用します。
1019
     *
1020
     * @param string $config_name Config 名称
0 ignored issues
show
introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
1021
     * @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...
1022
     * @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...
1023
     * @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...
1024
     * @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...
1025
     * @return Application
1026
     */
1027 1191
    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...
1028
    {
1029 1191
        $ymlPath = $ymlPath ? $ymlPath : __DIR__.'/../../app/config/eccube';
1030 1191
        $distPath = $distPath ? $distPath : __DIR__.'/../../src/Eccube/Resource/config';
1031 1191
        $config = array();
1032 1191
        $config_php = $ymlPath.'/'.$config_name.'.php';
1033 1191
        if (!file_exists($config_php)) {
1034 1191
            $config_yml = $ymlPath.'/'.$config_name.'.yml';
1035 1191
            if (file_exists($config_yml)) {
1036 1191
                $config = Yaml::parse(file_get_contents($config_yml));
1037 1191
                $config = empty($config) ? array() : $config;
1038 1191 View Code Duplication
                if (isset($this['output_config_php']) && $this['output_config_php']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1039 1191
                    file_put_contents($config_php, sprintf('<?php return %s', var_export($config, true)).';');
1040
                }
1041
            }
1042
        } else {
1043
            $config = require $config_php;
1044
        }
1045
1046 1191
        $config_dist = array();
1047 1191
        $config_php_dist = $distPath.'/'.$config_name.'.dist.php';
1048 1191
        if (!file_exists($config_php_dist)) {
1049 1191
            $config_yml_dist = $distPath.'/'.$config_name.'.yml.dist';
1050 1191
            if (file_exists($config_yml_dist)) {
1051 1191
                $config_dist = Yaml::parse(file_get_contents($config_yml_dist));
1052 1191 View Code Duplication
                if (isset($this['output_config_php']) && $this['output_config_php']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1053 1191
                    file_put_contents($config_php_dist, sprintf('<?php return %s', var_export($config_dist, true)).';');
1054
                }
1055
            }
1056
        } else {
1057
            $config_dist = require $config_php_dist;
1058
        }
1059
1060 1191
        if ($wrap_key) {
1061 1191
            $configAll = array_replace_recursive($configAll, array($config_name => $config_dist), array($config_name => $config));
1062
        } else {
1063 1191
            $configAll = array_replace_recursive($configAll, $config_dist, $config);
1064
        }
1065
1066 1191
        return $this;
1067
    }
1068
1069
    /**
1070
     * セッションが開始されているかどうか.
1071
     *
1072
     * @return boolean セッションが開始済みの場合 true
1073
     * @link http://php.net/manual/ja/function.session-status.php#113468
1074
     */
1075 1187
    protected function isSessionStarted()
1076
    {
1077 1187
        if (php_sapi_name() !== 'cli') {
1078 1187
            if (version_compare(phpversion(), '5.4.0', '>=')) {
1079 1187
                return session_status() === PHP_SESSION_ACTIVE ? true : false;
1080
            } else {
1081
                return session_id() === '' ? false : true;
1082
            }
1083
        }
1084
1085
        return false;
1086
    }
1087
1088
    /**
1089
     * Http Cache対応
1090
     */
1091 1187
    protected function initCacheRequest()
1092
    {
1093
        // httpキャッシュが無効の場合はイベント設定を行わない.
1094 1187
        if (!$this['config']['http_cache']['enabled']) {
1095 1187
            return;
1096
        }
1097
1098
        $app = $this;
1099
1100
        // Response Event(http cache対応、event実行は一番遅く設定)
1101
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
1102
1103
            if (!$event->isMasterRequest()) {
1104
                return;
1105
            }
1106
1107
            $request = $event->getRequest();
1108
            $response = $event->getResponse();
1109
1110
            $route = $request->attributes->get('_route');
1111
1112
            $etag = md5($response->getContent());
1113
1114
            if (strpos($route, 'admin') === 0) {
1115
                // 管理画面
1116
1117
                // 管理画面ではコンテンツの中身が変更された時点でキャッシュを更新し、キャッシュの適用範囲はprivateに設定
1118
                $response->setCache(array(
1119
                    'etag' => $etag,
1120
                    'private' => true,
1121
                ));
1122
1123
                if ($response->isNotModified($request)) {
1124
                    return $response;
1125
                }
1126
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
1127
            } else {
1128
                // フロント画面
1129
                $cacheRoute = $app['config']['http_cache']['route'];
1130
1131
                if (in_array($route, $cacheRoute) === true) {
1132
                    // キャッシュ対象となる画面lが含まれていた場合、キャッシュ化
1133
                    // max-ageを設定しているためExpiresは不要
1134
                    // Last-Modifiedだと比較する項目がないためETagで対応
1135
                    // max-ageを設定していた場合、contentの中身が変更されても変更されない
1136
1137
                    $age = $app['config']['http_cache']['age'];
1138
1139
                    $response->setCache(array(
1140
                        'etag' => $etag,
1141
                        'max_age' => $age,
1142
                        's_maxage' => $age,
1143
                        'public' => true,
1144
                    ));
1145
1146
                    if ($response->isNotModified($request)) {
1147
                        return $response;
1148
                    }
1149
                }
1150
            }
1151
1152
        }, -1024);
1153
    }
1154
1155
    /**
1156
     * すべてのプラグインの設定情報を返す.
1157
     *
1158
     * すべてのプラグインの config.yml 及び event.yml を読み込み、連想配列で返す.
1159
     * キャッシュファイルが存在する場合は、キャッシュを利用する.
1160
     * キャッシュファイルが存在しない場合は、キャッシュを生成する.
1161
     * $app['debug'] = true の場合は、キャッシュを利用しない.
1162
     *
1163
     * @return array
1164
     */
1165 1188
    public function getPluginConfigAll()
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
1166
    {
1167 1188
        if ($this['debug']) {
1168 1187
            return $this->parsePluginConfigs();
1169
        }
1170 2
        $pluginConfigCache = $this->getPluginConfigCacheFile();
1171 2
        if (file_exists($pluginConfigCache)) {
1172 1
            return require $pluginConfigCache;
1173
        }
1174 2
        if ($this->writePluginConfigCache($pluginConfigCache) === false) {
1175
            return $this->parsePluginConfigs();
1176
        } else {
1177 2
            return require $pluginConfigCache;
1178
        }
1179
    }
1180
1181
    /**
1182
     * プラグイン設定情報のキャッシュを書き込む.
1183
     *
1184
     * @param string $cacheFile
1185
     * @return int|boolean file_put_contents() の結果
1186
     */
1187 7
    public function writePluginConfigCache($cacheFile = null)
1188
    {
1189 7
        if (is_null($cacheFile)) {
1190 6
            $cacheFile = $this->getPluginConfigCacheFile();
1191
        }
1192 7
        $pluginConfigs = $this->parsePluginConfigs();
1193 7
        if (!file_exists($this['config']['plugin_temp_realdir'])) {
1194 1
            @mkdir($this['config']['plugin_temp_realdir']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1195
        }
1196 7
        $this['monolog']->debug("write plugin config cache", array($pluginConfigs));
1197 7
        return file_put_contents($cacheFile, sprintf('<?php return %s', var_export($pluginConfigs, true)).';');
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
1198
    }
1199
1200
    /**
1201
     * プラグイン設定情報のキャッシュファイルを削除する.
1202
     *
1203
     * @return boolean
1204
     */
1205 9
    public function removePluginConfigCache()
1206
    {
1207 9
        $cacheFile = $this->getPluginConfigCacheFile();
1208 9
        if (file_exists($cacheFile)) {
1209 8
            $this['monolog']->debug("remove plugin config cache");
1210 8
            return unlink($cacheFile);
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
1211
        }
1212 5
        return false;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
1213
    }
1214
1215
    /**
1216
     * プラグイン設定情報のキャッシュファイルパスを返す.
1217
     *
1218
     * @return string
1219
     */
1220 10
    public function getPluginConfigCacheFile()
1221
    {
1222 10
        return $this['config']['plugin_temp_realdir'].'/config_cache.php';
1223
    }
1224
1225
    /**
1226
     * プラグイン設定情報をパースし, 連想配列で返す.
1227
     *
1228
     * すべてのプラグインを探索し、 config.yml 及び event.yml をパースする.
1229
     * パースした情報を連想配列で返す.
1230
     *
1231
     * @return array
1232
     */
1233 1188
    public function parsePluginConfigs()
1234
    {
1235
1236 1188
        $finder = Finder::create()
1237 1188
            ->in($this['config']['plugin_realdir'])
1238 1188
            ->directories()
1239 1188
            ->depth(0);
1240 1188
        $finder->sortByName();
1241
1242 1188
        $pluginConfigs = array();
1243 1188
        foreach ($finder as $dir) {
1244 146
            $code = $dir->getBaseName();
1245 146
            if (!$code) {
1246
                //PHP5.3のgetBaseNameバグ対応
1247
                if (PHP_VERSION_ID < 50400) {
1248
                    $code = $dir->getFilename();
1249
                }
1250
            }
1251 146
            $file = $dir->getRealPath().'/config.yml';
1252 146
            $config = null;
0 ignored issues
show
Unused Code introduced by
$config is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1253 146 View Code Duplication
            if (file_exists($file)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1254 146
                $config = Yaml::parse(file_get_contents($file));
1255
            } else {
1256
                $this['monolog']->warning("skip {$code} orm.path loading. config.yml not found.", array('path' => $file));
1257
                continue;
1258
            }
1259
1260 146
            $file = $dir->getRealPath().'/event.yml';
1261 146
            $event = null;
1262 146 View Code Duplication
            if (file_exists($file)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1263 142
                $event = Yaml::parse(file_get_contents($file));
1264
            } else {
1265 4
                $this['monolog']->info("skip {$code} event.yml not found.", array('path' => $file));
1266
            }
1267 146
            if (!is_null($config)) {
1268 146
                $pluginConfigs[$code] = array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
1269 146
                    'config' => $config,
1270 146
                    'event' => $event
1271
                );
1272 1188
                $this['monolog']->debug("parse {$code} config", array($code => $pluginConfigs[$code]));
1273
            }
1274
        }
1275
1276 1188
        return $pluginConfigs;
1277
    }
1278
}
1279