Application   F
last analyzed

Complexity

Total Complexity 158

Size/Duplication

Total Lines 1238
Duplicated Lines 14.86 %

Coupling/Cohesion

Components 2
Dependencies 56

Test Coverage

Coverage 82.01%

Importance

Changes 0
Metric Value
dl 184
loc 1238
ccs 465
cts 567
cp 0.8201
rs 0.5217
c 0
b 0
f 0
wmc 158
lcom 2
cbo 56

29 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 8 2
A clearInstance() 0 4 1
A __clone() 0 4 1
A __construct() 0 14 2
A isBooted() 0 4 1
A initConfig() 0 20 1
A initLogger() 0 5 1
B initialize() 0 87 6
B initLocale() 0 28 5
C initMailer() 0 29 8
B initSession() 0 24 3
D initRendering() 0 129 17
F initDoctrine() 0 87 12
B initSecurity() 0 106 4
B initProxy() 3 12 5
A initializePlugin() 0 14 2
D initPluginEventDispatcher() 152 204 20
D loadPlugin() 12 105 20
A setTestMode() 0 4 1
A isTestMode() 0 4 1
B checkDatabaseConnection() 0 24 3
D parseConfig() 6 41 13
B isSessionStarted() 0 12 5
B initCacheRequest() 0 63 7
A getPluginConfigAll() 0 15 4
A writePluginConfigCache() 0 12 3
A removePluginConfigCache() 0 9 2
A getPluginConfigCacheFile() 0 4 1
C parsePluginConfigs() 11 45 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

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

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

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

1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
namespace Eccube;
25
26
use 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 1195
    public static function getInstance(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
50
    {
51 1195
        if (!is_object(self::$instance)) {
52 1188
            self::$instance = new Application($values);
53
        }
54
55 1195
        return self::$instance;
56
    }
57
58 1189
    public static function clearInstance()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
59
    {
60 1189
        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 1193
    public function __construct(array $values = array())
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
69
    {
70 1193
        parent::__construct($values);
71
72 1193
        if (is_null(self::$instance)) {
73 1189
            self::$instance = $this;
74
        }
75
76
        // load config
77 1193
        $this->initConfig();
78
79
        // init monolog
80 1193
        $this->initLogger();
81
    }
82
83
    /**
84
     * Application::runが実行されているか親クラスのプロパティから判定
85
     *
86
     * @return bool
87
     */
88 1194
    public function isBooted()
89
    {
90 1194
        return $this->booted;
91
    }
92
93 1193
    public function initConfig()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
94
    {
95
        // load config
96 1193
        $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 1193
            $configAll = array();
99 1193
            $app->parseConfig('constant', $configAll)
100 1193
                ->parseConfig('path', $configAll)
101 1193
                ->parseConfig('config', $configAll)
102 1193
                ->parseConfig('database', $configAll)
103 1193
                ->parseConfig('mail', $configAll)
104 1193
                ->parseConfig('log', $configAll)
105 1193
                ->parseConfig('nav', $configAll, true)
106 1193
                ->parseConfig('doctrine_cache', $configAll)
107 1193
                ->parseConfig('http_cache', $configAll)
108 1193
                ->parseConfig('session_handler', $configAll);
109
110 1193
            return $configAll;
111 1193
        });
112
    }
113
114 1195
    public function initLogger()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
115
    {
116 1195
        $app = $this;
117 1195
        $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 1192
    public function initialize()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
121
    {
122 1192
        if ($this->initialized) {
123 4
            return;
124
        }
125
126
        // init locale
127 1189
        $this->initLocale();
128
129
        // init session
130 1189
        if (!$this->isSessionStarted()) {
131 1189
            $this->initSession();
132
        }
133
134
        // init twig
135 1189
        $this->initRendering();
136
137
        // init provider
138 1189
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
139 1189
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
140
        ));
141 1189
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
142 1189
        $this->register(new \Silex\Provider\UrlGeneratorServiceProvider());
143 1189
        $this->register(new \Silex\Provider\FormServiceProvider());
144 1189
        $this->register(new \Silex\Provider\SerializerServiceProvider());
145 1189
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
146 1189
        $this->register(new MobileDetectServiceProvider());
147
148 1189
        $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 1189
        });
174
175
        // init mailer
176 1189
        $this->initMailer();
177
178
        // init doctrine orm
179 1189
        $this->initDoctrine();
180
181
        // Set up the DBAL connection now to check for a proper connection to the database.
182 1189
        $this->checkDatabaseConnection();
183
184
        // init security
185 1189
        $this->initSecurity();
186
187
        // init proxy
188 1189
        $this->initProxy();
189
190
        // init ec-cube service provider
191 1189
        $this->register(new ServiceProvider\EccubeServiceProvider());
192 1189
193 1189
        // mount controllers
194 1189
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
195
        $this->mount('', new ControllerProvider\FrontControllerProvider());
196
        $this->mount('/'.trim($this['config']['admin_route'], '/').'/', new ControllerProvider\AdminControllerProvider());
197 1189
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
198
199
        // add transaction listener
200 1189
        $this['dispatcher']->addSubscriber(new TransactionListener($this));
201
202 1189
        // init http cache
203
        $this->initCacheRequest();
204
205 1189
        $this->initialized = true;
206
    }
207
208
    public function initLocale()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
209 1189
    {
210 1189
211
        // timezone
212
        if (!empty($this['config']['timezone'])) {
213 1189
            date_default_timezone_set($this['config']['timezone']);
214 1189
        }
215 1189
216
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
217
            'locale' => $this['config']['locale'],
218 832
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
219
        ));
220 832
        $this['translator'] = $this->share($this->extend('translator', function ($translator, \Silex\Application $app) {
221 832
            $translator->addLoader('yaml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
222 832
223
            $file = __DIR__.'/Resource/locale/validator.'.$app['locale'].'.yml';
224
            if (file_exists($file)) {
225 832
                $translator->addResource('yaml', $file, $app['locale'], 'validators');
226 832
            }
227 832
228
            $file = __DIR__.'/Resource/locale/message.'.$app['locale'].'.yml';
229
            if (file_exists($file)) {
230 832
                $translator->addResource('yaml', $file, $app['locale']);
231 1189
            }
232
233
            return $translator;
234 1189
        }));
235
    }
236 1189
237 1189
    public function initSession()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
238
    {
239 1189
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
240 1189
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
241 1189
            'session.storage.options' => array(
242 1189
                'name' => $this['config']['cookie_name'],
243
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
244
                'cookie_secure' => $this['config']['force_ssl'],
245
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
246
                'cookie_httponly' => true,
247
                // cookie_domainは指定しない
248
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
249 1189
            ),
250
        ));
251 1189
252
        $options = $this['config']['session_handler'];
253
254
        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 1189
        }
260
    }
261 1189
262 1189
    public function initRendering()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
263
    {
264
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
265 585
            'twig.form.templates' => array('Form/form_layout.twig'),
266 585
        ));
267
        $this['twig'] = $this->share($this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
268 585
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
269 1189
            $twig->addExtension(new \Twig_Extension_StringLoader());
270
271
            return $twig;
272 574
        }));
273 574
274 574
        $this->before(function (Request $request, \Silex\Application $app) {
275 574
            $app['admin'] = false;
276 312
            $app['front'] = false;
277
            $pathinfo = rawurldecode($request->getPathInfo());
278 264
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
279
                $app['admin'] = true;
280
            } else {
281
                $app['front'] = true;
282
            }
283 572
284
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
285
            $app['twig'] = $app->share($app->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
286 572
                $paths = array();
287
288
                // 互換性がないのでprofiler とproduction 時のcacheを分離する
289 572
                if (isset($app['profiler'])) {
290
                    $cacheBaseDir = __DIR__.'/../../app/cache/twig/profiler/';
291
                } else {
292 572
                    $cacheBaseDir = __DIR__.'/../../app/cache/twig/production/';
293 312
                }
294 312
295
                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 312
                    }
299
                    $paths[] = $app['config']['template_admin_realdir'];
300
                    $paths[] = __DIR__.'/../../app/Plugin';
301 262
                    $cache = $cacheBaseDir.'admin';
302 262
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
303
                } else {
304 262
                    if (file_exists($app['config']['template_realdir'])) {
305 262
                        $paths[] = $app['config']['template_realdir'];
306 262
                    }
307 262
                    $paths[] = $app['config']['template_default_realdir'];
308
                    $paths[] = __DIR__.'/../../app/Plugin';
309 572
                    $cache = $cacheBaseDir.$app['config']['template_code'];
310 572
                    $app['front'] = true;
311
                }
312 572
                $twig->setCache($cache);
313 574
                $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
314
315
                return $twig;
316 574
            }));
317
318 312
            // 管理画面のIP制限チェック.
319 312
            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
                $allowHost = $app['config']['admin_allow_host'];
322
                if (count($allowHost) > 0) {
323
                    if (array_search($app['request']->getClientIp(), $allowHost) === false) {
324
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
325 1189
                    }
326
                }
327
            }
328 1189
        }, self::EARLY_EVENT);
329
330
        // twigのグローバル変数を定義.
331
        $app = $this;
332 572
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {
333 213
            // 未ログイン時にマイページや管理画面以下にアクセスすると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
            if (isset($app['twig_global_initialized']) && $app['twig_global_initialized'] === true) {
336 572
                return;
337 572
            }
338
            // ショップ基本情報
339 572
            $BaseInfo = $app['eccube.repository.base_info']->get();
340
            $app['twig']->addGlobal('BaseInfo', $BaseInfo);
341
342 312
            if ($app->isAdminRequest()) {
343 312
                // 管理画面
344
                // 管理画面メニュー
345 312
                $menus = array('', '', '');
346 312
                $app['twig']->addGlobal('menus', $menus);
347
348 306
                $Member = $app->user();
349
                if (is_object($Member)) {
350 306
                    // ログインしていれば管理者のロールを取得
351 306
                    $AuthorityRoles = $app['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
352
353 306
                    $roles = array();
354
                    foreach ($AuthorityRoles as $AuthorityRole) {
355
                        // 管理画面でメニュー制御するため相対パス全てをセット
356 312
                        $roles[] = $app['request']->getBaseUrl().'/'.$app['config']['admin_route'].$AuthorityRole->getDenyUrl();
357
                    }
358
359
                    $app['twig']->addGlobal('AuthorityRoles', $roles);
360
                }
361 260
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
362 260
            } else {
363
                // フロント画面
364
                $request = $event->getRequest();
365 260
                $route = $request->attributes->get('_route');
366 2
367 2
                // ユーザ作成画面
368
                if ($route === 'user_data') {
369 258
                    $params = $request->attributes->get('_route_params');
370
                    $route = $params['route'];
371
                    // プレビュー画面
372
                } elseif ($request->get('preview')) {
373
                    $route = 'preview';
374 260
                }
375 260
376 260
                try {
377 145
                    $DeviceType = $app['eccube.repository.master.device_type']
378 145
                        ->find(\Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
379
                    $PageLayout = $app['eccube.repository.page_layout']->getByUrl($DeviceType, $route);
380
                } catch (\Doctrine\ORM\NoResultException $e) {
381 260
                    $PageLayout = $app['eccube.repository.page_layout']->newPageLayout($DeviceType);
382 260
                }
383
384
                $app['twig']->addGlobal('PageLayout', $PageLayout);
385 572
                $app['twig']->addGlobal('title', $PageLayout->getName());
386 1189
            }
387
388
            $app['twig_global_initialized'] = true;
389 1189
        });
390
    }
391
392
    public function initMailer()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
393 1189
    {
394 1189
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
        if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
397
            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 1189
            }
405 1189
        }
406
407 1189
        $this->register(new \Silex\Provider\SwiftmailerServiceProvider());
408
        $this['swiftmailer.options'] = $this['config']['mail'];
409
410
        if (isset($this['config']['mail']['spool']) && is_bool($this['config']['mail']['spool'])) {
411 1189
            $this['swiftmailer.use_spool'] = $this['config']['mail']['spool'];
412 1189
        }
413
        // デフォルトはsmtpを使用
414 1189
        $transport = $this['config']['mail']['transport'];
415
        if ($transport == 'sendmail') {
416
            $this['swiftmailer.transport'] = \Swift_SendmailTransport::newInstance();
417
        } elseif ($transport == 'mail') {
418
            $this['swiftmailer.transport'] = \Swift_MailTransport::newInstance();
419 1189
        }
420
    }
421 1189
422
    public function initDoctrine()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
423 1189
    {
424
        $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 1189
            'dbs.options' => array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
426
                '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 1189
        $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Silex\Provider\DoctrineOrmManagerRegistryProvider());
429 1189
430 1189
        // プラグインのmetadata定義を合わせて行う.
431
        $pluginConfigs = $this->getPluginConfigAll();
432
        $ormMappings = array();
433
        $ormMappings[] = array(
434
            'type' => 'yml',
435
            'namespace' => 'Eccube\Entity',
436
            'path' => array(
437
                __DIR__.'/Resource/doctrine',
438
                __DIR__.'/Resource/doctrine/master',
439 1189
            ),
440 140
        );
441
442 140
        foreach ($pluginConfigs as $code) {
443
            $config = $code['config'];
444
            // Doctrine Extend
445
            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 1189
                $ormMappings[] = array(
451
                    'type' => 'yml',
452
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
453
                    'path' => $paths,
454
                );
455
            }
456 1189
        }
457
458
        $options = array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
459 1189
            'mappings' => $ormMappings
460 1
        );
461 1
462 1
        if (!$this['debug']) {
463
            $cacheDrivers = array();
464
            if (array_key_exists('doctrine_cache', $this['config'])) {
465 1
                $cacheDrivers = $this['config']['doctrine_cache'];
466 1
            }
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
            if (array_key_exists('hydration_cache', $cacheDrivers)) {
478
                $options['hydration_cache'] = $cacheDrivers['hydration_cache'];
479 1189
            }
480 1189
        }
481 1189
482
        $this->register(new \Dflydev\Silex\Provider\DoctrineOrm\DoctrineOrmServiceProvider(), array(
483
            'orm.proxies_dir' => __DIR__.'/../../app/cache/doctrine/proxies',
484
            '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 1189
         * YamlDriverのPHP7対応. Doctrine2.4で修正されれば不要.
495
         * @see https://github.com/EC-CUBE/ec-cube/issues/1338
496 1189
         */
497
        $config = $this['orm.em']->getConfiguration();
498 1189
        /** @var $driver \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain */
499 1189
        $chain = $config->getMetadataDriverImpl();
500
        // $ormMappingsの1要素ごとにDriverが生成されている.
501 1189
        $drivers = $chain->getDrivers();
502
        foreach ($drivers as $namespace => $oldDriver) {
503 1189
            /** @var $newDriver \Eccube\Doctrine\ORM\Mapping\Driver\YamlDriver */
504
            $newDriver = new YamlDriver($oldDriver->getLocator());
505
            // 修正したDriverに差し替える. メソッド名はaddだけど実際はsetしてる.
506
            $chain->addDriver($newDriver, $namespace);
507 1191
        }
508
    }
509 1189
510 1189
    public function initSecurity()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
511
    {
512 1189
        $this->register(new \Silex\Provider\SecurityServiceProvider());
513
        $this->register(new \Silex\Provider\RememberMeServiceProvider());
514 1189
515
        $this['security.firewalls'] = array(
516 1189
            'admin' => array(
517 1189
                'pattern' => "^/{$this['config']['admin_route']}/",
518 1189
                'form' => array(
519 1189
                    'login_path' => "/{$this['config']['admin_route']}/login",
520
                    'check_path' => "/{$this['config']['admin_route']}/login_check",
521
                    'username_parameter' => 'login_id',
522
                    'password_parameter' => 'password',
523
                    'with_csrf' => true,
524 1189
                    'use_forward' => true,
525 1189
                ),
526
                'logout' => array(
527 1189
                    'logout_path' => "/{$this['config']['admin_route']}/logout",
528
                    'target_url' => "/{$this['config']['admin_route']}/",
529 1189
                ),
530
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Member'),
531 1189
                'anonymous' => true,
532
            ),
533
            'customer' => array(
534
                '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 1189
                    'target_url' => '/',
546 1189
                ),
547
                'remember_me' => array(
548
                    'key' => sha1($this['config']['auth_magic']),
549 1189
                    'name' => $this['config']['cookie_name'].'_rememberme',
550 1189
                    // 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
                    'path' => $this['config']['root_urlpath'] ?: '/',
553 1189
                    'secure' => $this['config']['force_ssl'],
554
                    'httponly' => true,
555 1189
                    'always_remember_me' => false,
556
                    'remember_me_parameter' => 'login_memory',
557
                ),
558
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Customer'),
559
                'anonymous' => true,
560 1189
            ),
561
        );
562 1189
563
        $channel = null;
564
        // 強制SSL
565
        if ($this['config']['force_ssl'] == \Eccube\Common\Constant::ENABLED) {
566 1189
            $channel = "https";
567 1189
        }
568 1189
569 1189
        $this['security.access_rules'] = array(
570 1189
            array("^/{$this['config']['admin_route']}/login", 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
571 1189
            array("^/{$this['config']['admin_route']}/", 'ROLE_ADMIN', $channel),
572 1189
            array('^/mypage/login', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
573
            array('^/mypage/withdraw_complete', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
574
            array('^/mypage/change', 'IS_AUTHENTICATED_FULLY', $channel),
575
            array('^/mypage', 'ROLE_USER', $channel),
576 1189
        );
577 1189
578
        $this['eccube.password_encoder'] = $this->share(function ($app) {
579 1189
            return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
580 1189
        });
581 1189
        $this['security.encoder_factory'] = $this->share(function ($app) {
582
            return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
583 1189
                'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
584
                'Eccube\Entity\Member' => $app['eccube.password_encoder'],
585 1189
            ));
586 1189
        });
587
        $this['eccube.event_listner.security'] = $this->share(function ($app) {
588 1191
            return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
589
        });
590 1191
        $this['user'] = function ($app) {
591
            $token = $app['security']->getToken();
592
593
            return ($token !== null) ? $token->getUser() : null;
594 1189
        };
595
596
        // ログイン時のイベントを設定.
597 1189
        $this['dispatcher']->addListener(\Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN, array($this['eccube.event_listner.security'], 'onInteractiveLogin'));
598
599 1189
        // Voterの設定
600 1189
        $app = $this;
601
        $this['authority_voter'] = $this->share(function ($app) {
602
            return new \Eccube\Security\Voter\AuthorityVoter($app);
603 1189
        });
604
605 1189
        $app['security.voters'] = $app->extend('security.voters', function ($voters) use ($app) {
606 1189
            $voters[] = $app['authority_voter'];
607
608
            return $voters;
609 1189
        });
610 1189
611
        $this['security.access_manager'] = $this->share(function ($app) {
612
            return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
613
        });
614 1189
615
    }
616 1189
617
    /**
618
     * ロードバランサー、プロキシサーバの設定を行う
619
     */
620
    public function initProxy()
621 1189
    {
622
        $config = $this['config'];
623
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
624 1189
            $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($config) {
625
                // サブリクエストのREMOTE_ADDRも動的に設定を行う必要があるため、KernelEvents::REQUESTを使用する
626 1189
                Request::setTrustedProxies(array_merge(array($event->getRequest()->server->get('REMOTE_ADDR')), $config['trusted_proxies']));
627
            }, self::EARLY_EVENT);
628 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 1189
            Request::setTrustedProxies($config['trusted_proxies']);
630
        }
631
    }
632
633 587
    public function initializePlugin()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
634 1189
    {
635
        if ($this->initializedPlugin) {
636 1189
            return;
637
        }
638
639
        // setup event dispatcher
640 574
        $this->initPluginEventDispatcher();
641 83
642
        // load plugin
643 574
        $this->loadPlugin();
644 574
645 1189
        $this->initializedPlugin = true;
646
    }
647
648 573
    public function initPluginEventDispatcher()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
649 83
    {
650
        // EventDispatcher
651 571
        $this['eccube.event.dispatcher'] = $this->share(function () {
652 571
            return new EventDispatcher();
653 571
        });
654 1189
655
        $app = $this;
656
657 560
        // hook point
658 83
        $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($app) {
659
            if (!$event->isMasterRequest()) {
660 560
                return;
661 560
            }
662 560
            $hookpoint = 'eccube.event.app.before';
663 1189
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
664
        }, self::EARLY_EVENT);
665
666 560 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 83
            if (!$event->isMasterRequest()) {
668
                return;
669 560
            }
670 560
            $route = $event->getRequest()->attributes->get('_route');
671 1189
            $hookpoint = "eccube.event.controller.$route.before";
672
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
673
        });
674 560
675 560 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 560
            if (!$event->isMasterRequest()) {
677 1189
                return;
678
            }
679
            $route = $event->getRequest()->attributes->get('_route');
680 560
            $hookpoint = "eccube.event.controller.$route.after";
681 83
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
682
        });
683 560
684 560
        $this->on(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($app) {
685 1189
            if (!$event->isMasterRequest()) {
686
                return;
687
            }
688
            $hookpoint = 'eccube.event.app.after';
689
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
690 573
        }, self::LATE_EVENT);
691 83
692
        $this->on(KernelEvents::TERMINATE, function (PostResponseEvent $event) use ($app) {
693
            $route = $event->getRequest()->attributes->get('_route');
694 573
            $hookpoint = "eccube.event.controller.$route.finish";
695
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
696 573
        });
697
698
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
699
            if (!$event->isMasterRequest()) {
700 573
                return;
701
            }
702
            $route = $event->getRequest()->attributes->get('_route');
703 573
            $app['eccube.event.dispatcher']->dispatch('eccube.event.render.'.$route.'.before', $event);
704
        });
705 573
706
        // Request Event
707 312 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
            if (!$event->isMasterRequest()) {
710 263
                return;
711
            }
712
713
            $route = $event->getRequest()->attributes->get('_route');
714 573
715
            if (is_null($route)) {
716 1189
                return;
717
            }
718
719
            $app['monolog']->debug('KernelEvents::REQUEST '.$route);
720
721 572
            // 全体
722 83
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.request', $event);
723
724
            if (strpos($route, 'admin') === 0) {
725 570
                // 管理画面
726
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.request', $event);
727 570
            } else {
728
                // フロント画面
729
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.request', $event);
730
            }
731 570
732
            // ルーティング単位
733
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.request", $event);
734 570
735
        }, 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 570
737
        // Controller Event
738 310 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
            if (!$event->isMasterRequest()) {
741 262
                return;
742
            }
743
744
            $route = $event->getRequest()->attributes->get('_route');
745 570
746 1189
            if (is_null($route)) {
747
                return;
748
            }
749
750 560
            $app['monolog']->debug('KernelEvents::CONTROLLER '.$route);
751 83
752
            // 全体
753
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.controller', $event);
754 560
755
            if (strpos($route, 'admin') === 0) {
756 560
                // 管理画面
757 1
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.controller', $event);
758
            } else {
759
                // フロント画面
760 559
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.controller', $event);
761
            }
762
763 559
            // ルーティング単位
764
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.controller", $event);
765 559
        });
766
767 305
        // 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
            if (!$event->isMasterRequest()) {
770 256
                return;
771
            }
772
773
            $route = $event->getRequest()->attributes->get('_route');
774 559
775 1189
            if (is_null($route)) {
776
                return;
777
            }
778
779
            $app['monolog']->debug('KernelEvents::RESPONSE '.$route);
780 22
781
            // ルーティング単位
782
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.response", $event);
783
784 22
            if (strpos($route, 'admin') === 0) {
785
                // 管理画面
786 22
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.response', $event);
787
            } else {
788
                // フロント画面
789
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.response', $event);
790 22
            }
791
792
            // 全体
793 22
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.response', $event);
794
        });
795 22
796
        // Exception Event
797 9 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
            if (!$event->isMasterRequest()) {
800 13
                return;
801
            }
802
803
            $route = $event->getRequest()->attributes->get('_route');
804 22
805 1189
            if (is_null($route)) {
806
                return;
807
            }
808
809
            $app['monolog']->debug('KernelEvents::EXCEPTION '.$route);
810 560
811
            // ルーティング単位
812 560
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.exception", $event);
813 1
814
            if (strpos($route, 'admin') === 0) {
815
                // 管理画面
816 559
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.exception', $event);
817
            } else {
818
                // フロント画面
819 559
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.exception', $event);
820
            }
821 559
822
            // 全体
823 305
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.exception', $event);
824
        });
825
826 256
        // 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
            $route = $event->getRequest()->attributes->get('_route');
830 559
831 1189
            if (is_null($route)) {
832
                return;
833
            }
834 1189
835
            $app['monolog']->debug('KernelEvents::TERMINATE '.$route);
836
837 1189
            // ルーティング単位
838 1189
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.terminate", $event);
839
840
            if (strpos($route, 'admin') === 0) {
841 1189
                // 管理画面
842 1189
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.terminate', $event);
843 1189
            } else {
844 1189
                // フロント画面
845
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.terminate', $event);
846 1189
            }
847 1
848
            // 全体
849
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.terminate', $event);
850
        });
851
    }
852 1
853
    public function loadPlugin()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
854 1189
    {
855
        // プラグインディレクトリを探索.
856
        $basePath = $this['config']['plugin_realdir'];
857
        $pluginConfigs = $this->getPluginConfigAll();
858
859 1189
        // ハンドラ優先順位をdbから持ってきてハッシュテーブルを作成
860
        $priorities = array();
861 142
        $handlers = $this['orm.em']
862
            ->getRepository('Eccube\Entity\PluginEventHandler')
863 142
            ->getHandlers();
864
865
        foreach ($handlers as $handler) {
866
            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 142
                $priority = \Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_DISABLED;
872
            }
873 142
            $priorities[$handler->getPlugin()->getClassName()][$handler->getEvent()][$handler->getHandler()] = $priority;
874 142
        }
875 142
876
        // プラグインをロードする.
877
        // config.yml/event.ymlの定義に沿ってインスタンスの生成を行い, イベント設定を行う.
878 142
        foreach ($pluginConfigs as $code => $pluginConfig) {
879
            // 正しい形式の pluginConfig のみ読み込む
880 2
            $path = $basePath.'/'.$code;
881 2
            try {
882
                $this['eccube.service.plugin']->checkPluginArchiveContent($path, $pluginConfig['config']);
883
            } catch (\Eccube\Exception\PluginException $e) {
884 2
                $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 2
                    'path' => $path,
886
                    'original-message' => $e->getMessage()
887
                ));
888 142
                continue;
889
            }
890 2
            $config = $pluginConfig['config'];
891
892
            $plugin = $this['orm.em']
893
                ->getRepository('Eccube\Entity\Plugin')
894 140
                ->findOneBy(array('code' => $config['code']));
895 140
896 140
            // const
897
            if (isset($config['const'])) {
898 140
                $this['config'] = $this->share($this->extend('config', function ($eccubeConfig) use ($config) {
899
                    $eccubeConfig[$config['code']] = array(
900
                        'const' => $config['const'],
901
                    );
902
903
                    return $eccubeConfig;
904
                }));
905 140
            }
906
907 140
            if ($plugin && $plugin->getEnable() == Constant::DISABLED) {
908
                // プラグインが無効化されていれば読み込まない
909 140
                continue;
910 140
            }
911 140
912 140
            // Type: Event
913
            if (isset($config['event'])) {
914
                $class = '\\Plugin\\'.$config['code'].'\\'.$config['event'];
915
                $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 140
                    $this['monolog']->warning("Event class for plugin {$code} not exists.", array(
919
                        'class' => $class,
920
                    ));
921
                    $eventExists = false;
922
                }
923
924
                if ($eventExists && isset($config['event'])) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
925 140
926
                    $subscriber = new $class($this);
927
928
                    foreach ($pluginConfig['event'] as $event => $handlers) {
929
                        foreach ($handlers as $handler) {
930
                            if (!isset($priorities[$config['event']][$event][$handler[0]])) { // ハンドラテーブルに登録されていない(ソースにしか記述されていない)ハンドラは一番後ろにする
931
                                $priority = \Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_LATEST;
932
                            } else {
933
                                $priority = $priorities[$config['event']][$event][$handler[0]];
934 1189
                            }
935
                            // 優先度が0のプラグインは登録しない
936
                            if (\Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_DISABLED != $priority) {
937
                                $this['eccube.event.dispatcher']->addListener($event, array($subscriber, $handler[0]), $priority);
938
                            }
939
                        }
940
                    }
941
                }
942
            }
943
            // Type: ServiceProvider
944
            if (isset($config['service'])) {
945 1179
                foreach ($config['service'] as $service) {
946
                    $class = '\\Plugin\\'.$config['code'].'\\ServiceProvider\\'.$service;
947 1179 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
                    $this->register(new $class($this));
954
                }
955 574
            }
956
        }
957 574
    }
958
959
    /**
960
     * PHPUnit を実行中かどうかを設定する.
961
     *
962
     * @param boolean $testMode PHPUnit を実行中の場合 true
963
     */
964
    public function setTestMode($testMode)
965
    {
966
        $this->testMode = $testMode;
967
    }
968
969
    /**
970 1189
     * PHPUnit を実行中かどうか.
971
     *
972 1189
     * @return boolean PHPUnit を実行中の場合 true
973 1188
     */
974
    public function isTestMode()
975
    {
976 1
        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
    protected function checkDatabaseConnection()
990
    {
991
        if ($this['debug']) {
992 1
            return;
993
        }
994
        try {
995
            $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 1193
            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 1193
1011 1193
        return true;
1012 1193
    }
1013 1193
1014 1193
    /**
1015 1193
     * Config ファイルをパースし、連想配列を返します.
1016 1193
     *
1017 1193
     * $config_name.yml ファイルをパースし、連想配列を返します.
1018 1193
     * $config_name.php が存在する場合は、 PHP ファイルに記述された連想配列を使用します。
1019 1193
     *
1020 1193
     * @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 1193
    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 1193
    {
1029 1193
        $ymlPath = $ymlPath ? $ymlPath : __DIR__.'/../../app/config/eccube';
1030 1193
        $distPath = $distPath ? $distPath : __DIR__.'/../../src/Eccube/Resource/config';
1031 1193
        $config = array();
1032 1193
        $config_php = $ymlPath.'/'.$config_name.'.php';
1033 1193
        if (!file_exists($config_php)) {
1034 1193
            $config_yml = $ymlPath.'/'.$config_name.'.yml';
1035
            if (file_exists($config_yml)) {
1036
                $config = Yaml::parse(file_get_contents($config_yml));
1037
                $config = empty($config) ? array() : $config;
1038 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
                    file_put_contents($config_php, sprintf('<?php return %s', var_export($config, true)).';');
1040
                }
1041 1193
            }
1042 1193
        } else {
1043
            $config = require $config_php;
1044 1193
        }
1045
1046
        $config_dist = array();
1047 1193
        $config_php_dist = $distPath.'/'.$config_name.'.dist.php';
1048
        if (!file_exists($config_php_dist)) {
1049
            $config_yml_dist = $distPath.'/'.$config_name.'.yml.dist';
1050
            if (file_exists($config_yml_dist)) {
1051
                $config_dist = Yaml::parse(file_get_contents($config_yml_dist));
1052 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
                    file_put_contents($config_php_dist, sprintf('<?php return %s', var_export($config_dist, true)).';');
1054
                }
1055
            }
1056 1189
        } else {
1057
            $config_dist = require $config_php_dist;
1058 1189
        }
1059 1189
1060 1189
        if ($wrap_key) {
1061
            $configAll = array_replace_recursive($configAll, array($config_name => $config_dist), array($config_name => $config));
1062
        } else {
1063
            $configAll = array_replace_recursive($configAll, $config_dist, $config);
1064
        }
1065
1066
        return $this;
1067
    }
1068
1069
    /**
1070
     * セッションが開始されているかどうか.
1071
     *
1072 1189
     * @return boolean セッションが開始済みの場合 true
1073
     * @link http://php.net/manual/ja/function.session-status.php#113468
1074
     */
1075 1189
    protected function isSessionStarted()
1076 1189
    {
1077
        if (php_sapi_name() !== 'cli') {
1078
            if (version_compare(phpversion(), '5.4.0', '>=')) {
1079
                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
    protected function initCacheRequest()
1092
    {
1093
        // httpキャッシュが無効の場合はイベント設定を行わない.
1094
        if (!$this['config']['http_cache']['enabled']) {
1095
            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 1190
                    if ($response->isNotModified($request)) {
1147
                        return $response;
1148 1190
                    }
1149 1189
                }
1150
            }
1151 2
1152 2
        }, -1024);
1153 1
    }
1154
1155 2
    /**
1156
     * すべてのプラグインの設定情報を返す.
1157
     *
1158 2
     * すべてのプラグインの config.yml 及び event.yml を読み込み、連想配列で返す.
1159
     * キャッシュファイルが存在する場合は、キャッシュを利用する.
1160
     * キャッシュファイルが存在しない場合は、キャッシュを生成する.
1161
     * $app['debug'] = true の場合は、キャッシュを利用しない.
1162
     *
1163
     * @return array
1164
     */
1165
    public function getPluginConfigAll()
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
1166
    {
1167
        if ($this['debug']) {
1168 7
            return $this->parsePluginConfigs();
1169
        }
1170 7
        $pluginConfigCache = $this->getPluginConfigCacheFile();
1171 6
        if (file_exists($pluginConfigCache)) {
1172
            return require $pluginConfigCache;
1173 7
        }
1174 7
        if ($this->writePluginConfigCache($pluginConfigCache) === false) {
1175 1
            return $this->parsePluginConfigs();
1176
        } else {
1177 7
            return require $pluginConfigCache;
1178 7
        }
1179
    }
1180
1181
    /**
1182
     * プラグイン設定情報のキャッシュを書き込む.
1183
     *
1184
     * @param string $cacheFile
1185
     * @return int|boolean file_put_contents() の結果
1186 9
     */
1187
    public function writePluginConfigCache($cacheFile = null)
1188 9
    {
1189 9
        if (is_null($cacheFile)) {
1190 8
            $cacheFile = $this->getPluginConfigCacheFile();
1191 8
        }
1192
        $pluginConfigs = $this->parsePluginConfigs();
1193 5
        if (!file_exists($this['config']['plugin_temp_realdir'])) {
1194
            @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
        $this['monolog']->debug("write plugin config cache", array($pluginConfigs));
1197
        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 10
     * プラグイン設定情報のキャッシュファイルを削除する.
1202
     *
1203 10
     * @return boolean
1204
     */
1205
    public function removePluginConfigCache()
1206
    {
1207
        $cacheFile = $this->getPluginConfigCacheFile();
1208
        if (file_exists($cacheFile)) {
1209
            $this['monolog']->debug("remove plugin config cache");
1210
            return unlink($cacheFile);
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
1211
        }
1212
        return false;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
1213
    }
1214 1190
1215
    /**
1216
     * プラグイン設定情報のキャッシュファイルパスを返す.
1217 1190
     *
1218 1190
     * @return string
1219 1190
     */
1220 1190
    public function getPluginConfigCacheFile()
1221 1190
    {
1222
        return $this['config']['plugin_temp_realdir'].'/config_cache.php';
1223 1190
    }
1224 1190
1225 146
    /**
1226 146
     * プラグイン設定情報をパースし, 連想配列で返す.
1227
     *
1228
     * すべてのプラグインを探索し、 config.yml 及び event.yml をパースする.
1229
     * パースした情報を連想配列で返す.
1230
     *
1231
     * @return array
1232 146
     */
1233 146
    public function parsePluginConfigs()
1234 146
    {
1235 146
1236
        $finder = Finder::create()
1237
            ->in($this['config']['plugin_realdir'])
1238
            ->directories()
1239
            ->depth(0);
1240
        $finder->sortByName();
1241 146
1242 146
        $pluginConfigs = array();
1243 146
        foreach ($finder as $dir) {
1244 142
            $code = $dir->getBaseName();
1245
            if (!$code) {
1246 4
                //PHP5.3のgetBaseNameバグ対応
1247
                if (PHP_VERSION_ID < 50400) {
1248 146
                    $code = $dir->getFilename();
1249 146
                }
1250 146
            }
1251 146
            $file = $dir->getRealPath().'/config.yml';
1252
            $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 1190 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
                $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 1190
                continue;
1258
            }
1259
1260
            $file = $dir->getRealPath().'/event.yml';
1261
            $event = null;
1262 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
                $event = Yaml::parse(file_get_contents($file));
1264
            } else {
1265
                $this['monolog']->info("skip {$code} event.yml not found.", array('path' => $file));
1266
            }
1267
            if (!is_null($config)) {
1268
                $pluginConfigs[$code] = array(
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
1269
                    'config' => $config,
1270
                    'event' => $event
1271
                );
1272
                $this['monolog']->debug("parse {$code} config", array($code => $pluginConfigs[$code]));
1273
            }
1274
        }
1275
1276
        return $pluginConfigs;
1277
    }
1278
}
1279