Failed Conditions
Pull Request — experimental/3.1 (#2270)
by Kentaro
116:16 queued 109:30
created

src/Eccube/Application.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
namespace Eccube;
25
26
use Doctrine\DBAL\Types\Type;
27
use Eccube\Application\ApplicationTrait;
28
use Eccube\Common\Constant;
29
use Eccube\Doctrine\DBAL\Types\UTCDateTimeType;
30
use Eccube\Doctrine\ORM\Mapping\Driver\YamlDriver;
31
use Eccube\EventListener\TransactionListener;
32
use Eccube\Plugin\ConfigManager as PluginConfigManager;
33
use Eccube\Routing\EccubeRouter;
34
use Eccube\ServiceProvider\EntityEventServiceProvider;
35
use Eccube\ServiceProvider\MobileDetectServiceProvider;
36
use Sergiors\Silex\Provider\AnnotationsServiceProvider;
37
use Sergiors\Silex\Provider\DoctrineCacheServiceProvider;
38
use Sergiors\Silex\Provider\RoutingServiceProvider;
39
use Sergiors\Silex\Provider\SensioFrameworkExtraServiceProvider;
40
use Sergiors\Silex\Provider\TemplatingServiceProvider;
41
use Sergiors\Silex\Routing\ChainUrlGenerator;
42
use Sergiors\Silex\Routing\ChainUrlMatcher;
43
use Symfony\Component\EventDispatcher\EventDispatcher;
44
use Symfony\Component\Finder\Finder;
45
use Symfony\Component\HttpFoundation\Request;
46
use Symfony\Component\HttpFoundation\Response;
47
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
48
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
49
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
50
use Symfony\Component\HttpKernel\KernelEvents;
51
use Symfony\Component\Yaml\Yaml;
52
53
class Application extends \Silex\Application
54
{
55
    use \Silex\Application\FormTrait;
56
    use \Silex\Application\UrlGeneratorTrait;
57
    use \Silex\Application\MonologTrait;
58
    use \Silex\Application\SwiftmailerTrait;
59
    use \Silex\Application\SecurityTrait;
60
    use \Silex\Application\TranslationTrait;
61
    use \Eccube\Application\ApplicationTrait;
62
    use \Eccube\Application\SecurityTrait;
63
    use \Eccube\Application\TwigTrait;
64
65
    protected static $instance;
66
67 1179
    protected $initialized = false;
68
    protected $initializedPlugin = false;
69 1179
    protected $testMode = false;
70 1178
71
    public static function getInstance(array $values = array())
72
    {
73 1179
        if (!is_object(self::$instance)) {
74
            self::$instance = new Application($values);
75
        }
76 1179
77
        return self::$instance;
78 1179
    }
79
80
    public static function clearInstance()
81
    {
82
        self::$instance = null;
83
    }
84
85
    final public function __clone()
86 1179
    {
87
        throw new \Exception('Clone is not allowed against '.get_class($this));
88 1179
    }
89
90 1179
    public function __construct(array $values = array())
91 1179
    {
92
        parent::__construct($values);
93
94
        if (is_null(self::$instance)) {
95 1179
            self::$instance = $this;
96
        }
97
98 1179
        // load config
99
        $this->initConfig();
100
101
        // init monolog
102
        $this->initLogger();
103
    }
104
105
    /**
106 1187
     * Application::runが実行されているか親クラスのプロパティから判定
107
     *
108 1187
     * @return bool
109
     */
110
    public function isBooted()
111 1179
    {
112
        return $this->booted;
113
    }
114
115 1179
    public function initConfig()
116 1179
    {
117 1179
        // load config
118 1179
        $this['config'] = function() {
119 1179
            $configAll = array();
120 1179
            $this->parseConfig('constant', $configAll)
121 1179
                ->parseConfig('path', $configAll)
122 1179
                ->parseConfig('config', $configAll)
123 1179
                ->parseConfig('database', $configAll)
124 1179
                ->parseConfig('mail', $configAll)
125 1179
                ->parseConfig('log', $configAll)
126
                ->parseConfig('nav', $configAll, true)
127 1179
                ->parseConfig('doctrine_cache', $configAll)
128
                ->parseConfig('http_cache', $configAll)
129
                ->parseConfig('session_handler', $configAll);
130
131 1179
            return $configAll;
132
        };
133 1179
    }
134 1179
135
    public function initLogger()
136
    {
137 1179
        $app = $this;
138
        $this->register(new ServiceProvider\LogServiceProvider($app));
139 1179
    }
140 4
141
    public function initialize()
142
    {
143
        if ($this->initialized) {
144 1179
            return;
145
        }
146
147 1179
        // init locale
148 1179
        $this->initLocale();
149
150
        // init session
151
        if (!$this->isSessionStarted()) {
152 1179
            $this->initSession();
153
        }
154
155 1179
        // init twig
156 1179
        $this->initRendering();
157
158 1179
        // init provider
159 1179
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
160 1179
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
161 1179
        ));
162
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
163
        $this->register(new \Silex\Provider\FormServiceProvider());
164 33
        $this->register(new \Silex\Provider\SerializerServiceProvider());
165 33
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
166
        $this->register(new MobileDetectServiceProvider());
167
168
        $this->error(function (\Exception $e, Request $request, $code) {
169
            if ($this['debug']) {
170
                return;
171
            }
172
173
            switch ($code) {
174
                case 403:
175
                    $title = 'アクセスできません。';
176
                    $message = 'お探しのページはアクセスができない状況にあるか、移動もしくは削除された可能性があります。';
177
                    break;
178
                case 404:
179
                    $title = 'ページがみつかりません。';
180
                    $message = 'URLに間違いがないかご確認ください。';
181
                    break;
182
                default:
183
                    $title = 'システムエラーが発生しました。';
184
                    $message = '大変お手数ですが、サイト管理者までご連絡ください。';
185
                    break;
186
            }
187 1179
188
            return $this->render('error.twig', array(
189
                'error_title' => $title,
190 1179
                'error_message' => $message,
191
            ));
192
        });
193 1179
194
        // init mailer
195
        $this->initMailer();
196 1179
197
        // init doctrine orm
198
        $this->initDoctrine();
199 1179
200
        // Set up the DBAL connection now to check for a proper connection to the database.
201 1179
        $this->checkDatabaseConnection();
202 1179
203 1179
        // init security
204 1179
        $this->initSecurity();
205 1179
206 1179
        $this->register(new \Sergiors\Silex\Provider\RoutingServiceProvider(), [
207 1179
            'routing.cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/routing'
208
        ]);
209 1179
        $this->register(new \Sergiors\Silex\Provider\DoctrineCacheServiceProvider());
210 1179
        $this->register(new \Sergiors\Silex\Provider\TemplatingServiceProvider());
211
        $this->register(new \Sergiors\Silex\Provider\AnnotationsServiceProvider(), [
212
            'annotations.debug' => $this['debug'],
213 1179
            'annotations.options' => [
214
                'cache_driver' => $this['debug'] ? 'array' : 'filesystem',
215
                'cache_dir' => $this['debug'] ? null : __DIR__.'/../../app/cache/annotation'
216
            ]
217 1179
        ]);
218
        $this->register(new \Sergiors\Silex\Provider\SensioFrameworkExtraServiceProvider(), [
219
            'request' => [
220 1179
                'auto_convert' => true
221
            ]
222
        ]);
223 1179
        // init proxy
224 1179
        $this->initProxy();
225 1179
226 1179
        // init ec-cube service provider
227
        $this->register(new ServiceProvider\EccubeServiceProvider());
228
229
        // mount controllers
230 1179
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
231
        $this->mount('', new ControllerProvider\FrontControllerProvider());
232
        $this->mount('/'.trim($this['config']['admin_route'], '/').'/', new ControllerProvider\AdminControllerProvider());
233 1178
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
234 1178
235 1178
        // ルーティングの設定
236 1178
        // TODO EccubeRoutingServiceProviderに移植する.
237 1178
        $app = $this;
238 1178
        $this['eccube.router'] = $this->protect(function($resoure, $cachePrefix) use ($app) {
239
            $options = [
240 1178
                'debug' => $app['debug'],
241 1178
                'cache_dir' => $app['routing.cache_dir'],
242
                'matcher_base_class' => $app['request_matcher_class'],
243
                'matcher_class' => $app['request_matcher_class'],
244 1178
                'matcher_cache_class' => $cachePrefix.'UrlMatcher',
245 1178
                'generator_cache_class' => $cachePrefix.'UrlGenerator'
246
            ];
247
            $router = new EccubeRouter(
248 1178
                $app['routing.loader'],
249 1178
                $resoure,
250 1178
                $options,
251
                $app['request_context'],
252 1178
                $app['logger']
253 1179
            );
254
255
            $router->setAdminPrefix($app['config']['admin_route']);
256 1178
            $router->setUserDataPrefix($app['config']['user_data_route']);
257 1178
            $router->setRequireHttps($app['config']['force_ssl']);
258
259 1178
            return $router;
260
        });
261
262
        $this['eccube.router.origin'] = function ($app) {
263
            $resource = __DIR__.'/Controller';
264 1178
            $cachePrefix = 'Origin';
265 1178
266 1178
            return $app['eccube.router']($resource, $cachePrefix);
267 1178
        };
268
269 1178
        $this['eccube.routers.plugin'] = function ($app) {
270 1178
            // TODO 有効なプラグインを対象とする必要がある.
271 1178
            $dirs = Finder::create()
272 1178
                ->in($app['config']['root_dir'].'/app/Plugin')
273 1178
                ->name('Controller')
274
                ->directories();
275
276 1178
            $routers = [];
277
            foreach ($dirs as $dir) {
278
                $realPath = $dir->getRealPath();
279
                $pluginCode = basename(dirname($realPath));
280
                $routers[] = $app['eccube.router']($realPath, 'Plugin'.$pluginCode);
281 1178
            }
282 1178
283
            return $routers;
284 1178
        };
285
286 1178
        $this['eccube.router.extend'] = function ($app) {
287
            // TODO ディレクトリ名は暫定
288
            $resource = $app['config']['root_dir'].'/app/Acme/Controller';
289
            $cachePrefix = 'Extend';
290 1178
291 1178
            $router = $app['eccube.router']($resource, $cachePrefix);
292 1178
293 1178
            return $router;
294
        };
295 1178
296 1178 View Code Duplication
        $this->extend('request_matcher', function ($matcher, $app) {
297
            $matchers = [];
298 1178
            $matchers[] = $app['eccube.router.extend'];
299 1179
            foreach ($app['eccube.routers.plugin'] as $router) {
300
                $matchers[] = $router;
301
            };
302 1178
            $matchers[] = $app['eccube.router.origin'];
303 1178
            $matchers[] = $matcher;
304 1178
305 1178
            return new ChainUrlMatcher($matchers, $app['request_context']);
306
        });
307 1178
308 1178 View Code Duplication
        $this->extend('url_generator', function ($generator, $app) {
309
            $generators = [];
310 1178
            $generators[] = $app['eccube.router.extend'];
311 1179
            foreach ($app['eccube.routers.plugin'] as $router) {
312
                $generators[] = $router;
313
            };
314 1179
            $generators[] = $app['eccube.router.origin'];
315
            $generators[] = $generator;
316 1179
317
            return new ChainUrlGenerator($generators, $app['request_context']);
318
        });
319 1179
320
        // init http cache
321
        $this->initCacheRequest();
322
323 1179
        $this->initialized = true;
324 1179
    }
325
326
    public function initLocale()
327 1179
    {
328 1179
329 1179
        // timezone
330
        if (!empty($this['config']['timezone'])) {
331
            date_default_timezone_set($this['config']['timezone']);
332
        }
333 1178
334
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
335 1178
            'locale' => $this['config']['locale'],
336 1178
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
337 1178
            'locale_fallbacks' => ['ja', 'en'],
338
        ));
339
        $this->extend('translator', function ($translator, \Silex\Application $app) {
340 1178
            $translator->addLoader('yaml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
341 1178
342 1178
            $file = __DIR__.'/Resource/locale/validator.'.$app['locale'].'.yml';
343
            if (file_exists($file)) {
344
                $translator->addResource('yaml', $file, $app['locale'], 'validators');
345 1178
            }
346 1179
347
            $file = __DIR__.'/Resource/locale/message.'.$app['locale'].'.yml';
348
            if (file_exists($file)) {
349 1179
                $translator->addResource('yaml', $file, $app['locale']);
350
            }
351 1179
352 1179
            return $translator;
353
        });
354 1179
    }
355 1179
356 1179
    public function initSession()
357 1179
    {
358
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
359
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
360
            'session.storage.options' => array(
361
                'name' => $this['config']['cookie_name'],
362
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
363
                'cookie_secure' => $this['config']['force_ssl'],
364 1179
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
365
                'cookie_httponly' => true,
366 1179
                // cookie_domainは指定しない
367
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
368
            ),
369
        ));
370
371
        $options = $this['config']['session_handler'];
372
373
        if ($options['enabled']) {
374 1179
            // @see http://silex.sensiolabs.org/doc/providers/session.html#custom-session-configurations
375
            $this['session.storage.handler'] = null;
376 1179
            ini_set('session.save_handler', $options['save_handler']);
377 1179
            ini_set('session.save_path', $options['save_path']);
378
        }
379
    }
380 1178
381 1178
    public function initRendering()
382
    {
383 1178
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
384 1179
            'twig.form.templates' => array('Form/form_layout.twig'),
385
        ));
386
        $this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
387 475
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
388 475
            $twig->addExtension(new \Twig_Extension_StringLoader());
389 475
390 475
            return $twig;
391 300
        });
392
393 177
        $this->before(function (Request $request, \Silex\Application $app) {
394
            $app['admin'] = $app['front'] = false;
395 475
            $pathinfo = rawurldecode($request->getPathInfo());
396 300
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
397 300
                $app['admin'] = true;
398
            } else {
399 300
                $app['front'] = true;
400 300
            }
401
402
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
403
            if ($app->isAdminRequest()) {
404 177
                if (file_exists(__DIR__.'/../../app/template/admin')) {
405 177
                    $paths[] = __DIR__.'/../../app/template/admin';
406
                }
407 177
                $paths[] = $app['config']['template_admin_realdir'];
408 177
                $paths[] = __DIR__.'/../../app/Plugin';
409
                $cacheDir =  __DIR__.'/../../app/cache/twig/admin';
410 177
            } else {
411
                switch ($app['mobile_detect.device_type']) {
412
                    case \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_SP:
413 475
                        // TODO 構成を要検討
414
                        if (file_exists(__DIR__.'/../../app/template/smartphone')) {
415
                            $paths[] = __DIR__.'/../../app/template/smartphone';
416 475
                        }
417
                        $paths[] = __DIR__.'/Resource/template/smartphone';
418
                        $paths[] = __DIR__.'/../../app/Plugin';
419
                        $cacheDir =  __DIR__.'/../../app/cache/twig/smartphone';
0 ignored issues
show
$cacheDir 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...
420
                        // $cacheDir =  __DIR__.'/../../app/cache/twig/'.$app['config']['template_code'];
421
                    default:
422
                    case \Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC:
0 ignored issues
show
case \Eccube\Entity\Mast...fig']['template_code']; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
423
                        if (file_exists($app['config']['template_realdir'])) {
424
                            $paths[] = $app['config']['template_realdir'];
425
                        }
426
                        $paths[] = $app['config']['template_default_realdir'];
427
                        $paths[] = __DIR__.'/../../app/Plugin';
428
                        $cacheDir =  __DIR__.'/../../app/cache/twig/'.$app['config']['template_code'];
429
                }
430
            }
431
            $app['twig']->setCache($app['debug'] ? null : $cacheDir);
432
            $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
433
434
            // 管理画面のIP制限チェック.
435
            if ($app->isAdminRequest()) {
436
                // IP制限チェック
437
                $allowHost = $app['config']['admin_allow_host'];
438
                if (count($allowHost) > 0) {
439
                    if (array_search($app['request_stack']->getCurrentRequest()->getClientIp(), $allowHost) === false) {
440
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
441
                    }
442
                }
443
            }
444
        }, self::EARLY_EVENT);
445
446
        // twigのグローバル変数を定義.
447
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) {
448
            // 未ログイン時にマイページや管理画面以下にアクセスするとSubRequestで実行されるため,
449
            // $event->isMasterRequest()ではなく、グローバル変数が初期化済かどうかの判定を行う
450
            if (isset($this['twig_global_initialized']) && $this['twig_global_initialized'] === true) {
451
                return;
452
            }
453 475
            // ショップ基本情報
454
            $BaseInfo = $this['eccube.repository.base_info']->get();
455 300
            $this['twig']->addGlobal('BaseInfo', $BaseInfo);
456 300
457
            if ($this->isAdminRequest()) {
458
                // 管理画面
459
                // 管理画面メニュー
460
                $menus = array('', '', '');
461
                $this['twig']->addGlobal('menus', $menus);
462 1179
463
                $Member = $this->user();
464
                if (is_object($Member)) {
465
                    // ログインしていれば管理者のロールを取得
466
                    $AuthorityRoles = $this['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
467
468 470
                    $roles = array();
469 122
                    $request = $event->getRequest();
470
                    foreach ($AuthorityRoles as $AuthorityRole) {
471
                        // 管理画面でメニュー制御するため相対パス全てをセット
472 470
                        $roles[] = $request->getBaseUrl().'/'.$this['config']['admin_route'].$AuthorityRole->getDenyUrl();
473 470
                    }
474
475 470
                    $this['twig']->addGlobal('AuthorityRoles', $roles);
476
                }
477
478 300
            } else {
479 300
                // フロント画面
480
                $request = $event->getRequest();
481 300
                $route = $request->attributes->get('_route');
482 300
483
                // ユーザ作成画面
484 294
                if ($route === 'user_data') {
485
                    $params = $request->attributes->get('_route_params');
486 294
                    $route = $params['route'];
487 294
                    // プレビュー画面
488 294
                } elseif ($request->get('preview')) {
489
                    $route = 'preview';
490 294
                }
491
492
                try {
493 300
                    $DeviceType = $this['eccube.repository.master.device_type']
494
                        ->find(\Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
495
                    $PageLayout = $this['eccube.repository.page_layout']->getByUrl($DeviceType, $route);
496
                } catch (\Doctrine\ORM\NoResultException $e) {
497
                    $PageLayout = $this['eccube.repository.page_layout']->newPageLayout($DeviceType);
498 170
                }
499 170
500
                $this['twig']->addGlobal('PageLayout', $PageLayout);
501
                $this['twig']->addGlobal('title', $PageLayout->getName());
502 170
            }
503 2
504 2
            $this['twig_global_initialized'] = true;
505
        });
506 168
    }
507
508
    public function initMailer()
509
    {
510
511 170
        // メール送信時の文字エンコード指定(デフォルトはUTF-8)
512 170
        if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
513 170
            if ($this['config']['mail']['charset_iso_2022_jp'] === true) {
514 69
                \Swift::init(function () {
515 69
                    \Swift_DependencyContainer::getInstance()
516
                        ->register('mime.qpheaderencoder')
517
                        ->asAliasOf('mime.base64headerencoder');
518 170
                    \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
519 170
                });
520
            }
521
        }
522 470
523 1179
        $this->register(new \Silex\Provider\SwiftmailerServiceProvider());
524
        $this['swiftmailer.options'] = $this['config']['mail'];
525
526 1179
        if (isset($this['config']['mail']['spool']) && is_bool($this['config']['mail']['spool'])) {
527
            $this['swiftmailer.use_spool'] = $this['config']['mail']['spool'];
528
        }
529
        // デフォルトはsmtpを使用
530 1179
        $transport = $this['config']['mail']['transport'];
531 1179
        if ($transport == 'sendmail') {
532
            $this['swiftmailer.transport'] = \Swift_SendmailTransport::newInstance();
533
        } elseif ($transport == 'mail') {
534
            $this['swiftmailer.transport'] = \Swift_MailTransport::newInstance();
535
        }
536
    }
537
538
    public function initDoctrine()
539
    {
540
        $this->register(new EntityEventServiceProvider());
541 1179
        $this->register(new \Silex\Provider\DoctrineServiceProvider(), array(
542 1179
            'dbs.options' => array(
543
                'default' => $this['config']['database']
544 1179
            )
545 1179
        ));
546
        $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Provider\DoctrineOrmManagerRegistryProvider());
547
548 1179
        // UTCで保存
549 1179
        // @see http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/cookbook/working-with-datetime.html
550
        Type::overrideType('datetime', UTCDateTimeType::class);
551 1179
        Type::overrideType('datetimetz', UTCDateTimeType::class);
552
553
        // プラグインのmetadata定義を合わせて行う.
554
        $pluginConfigs = PluginConfigManager::getPluginConfigAll($this['debug']);
555
        $ormMappings = array();
556 1179
        $ormMappings[] = array(
557
            'type' => 'yml',
558 1179
            'namespace' => 'Eccube\Entity',
559 1179
            'path' => array(
560
                __DIR__.'/Resource/doctrine',
561 1179
                __DIR__.'/Resource/doctrine/master',
562
            ),
563
        );
564
        // ここを有効にすると本体の Entity でもアノテーションが使える
565 1179
        // が、 Yaml との共存はできない模様...
566 1179
        // $ormMappings[] = array(
567
        //     'type' => 'annotation',
568
        //     'namespace' => 'Eccube\Entity',
569
        //     'path' => array(
570 1179
        //         __DIR__.'/Entity',
571 1179
        //         __DIR__.'/Entity/master',
572 1179
        //     ),
573
        //     'use_simple_annotation_reader' => false,
574
        // );
575
576
        // TODO namespace は暫定
577
        $ormMappings[] = array(
578
            'type' => 'annotation',
579
            'namespace' => 'Acme\Entity',
580
            'path' => array(
581
                __DIR__.'/../../app/Acme/Entity',
582
            ),
583
            'use_simple_annotation_reader' => false,
584
        );
585
586
        foreach ($pluginConfigs as $code) {
587
            $config = $code['config'];
588
            // Doctrine Extend
589
            if (isset($config['orm.path']) && is_array($config['orm.path'])) {
590
                $paths = array();
591 View Code Duplication
                foreach ($config['orm.path'] as $path) {
592
                    $paths[] = $this['config']['plugin_realdir'].'/'.$config['code'].$path;
593 1179
                }
594
                $ormMappings[] = array(
595
                    'type' => 'yml',
596
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
597
                    'path' => $paths,
598
                );
599
                $ormMappings[] = array(
600
                    'type' => 'annotation',
601
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
602 1179
                    'path' => $paths,
603 1179
                    'use_simple_annotation_reader' => false,
604
                );
605 1179
            }
606 1179
        }
607 1179
608 1179
        $options = array(
609
            'mappings' => $ormMappings
610 1179
        );
611 1179
612 1179
        if (!$this['debug']) {
613 1179
            $cacheDrivers = array();
614
            if (array_key_exists('doctrine_cache', $this['config'])) {
615 1179
                $cacheDrivers = $this['config']['doctrine_cache'];
616 1179
            }
617 1179
618 1179
            if (array_key_exists('metadata_cache', $cacheDrivers)) {
619
                $options['metadata_cache'] = $cacheDrivers['metadata_cache'];
620
            }
621
            if (array_key_exists('query_cache', $cacheDrivers)) {
622
                $options['query_cache'] = $cacheDrivers['query_cache'];
623
            }
624
            if (array_key_exists('result_cache', $cacheDrivers)) {
625 1179
                $options['result_cache'] = $cacheDrivers['result_cache'];
626
            }
627
            if (array_key_exists('hydration_cache', $cacheDrivers)) {
628 1179
                $options['hydration_cache'] = $cacheDrivers['hydration_cache'];
629
            }
630
        }
631
632
        $this->register(new \Dflydev\Provider\DoctrineOrm\DoctrineOrmServiceProvider(), array(
633
            'orm.proxies_dir' => __DIR__.'/../../app/cache/doctrine/proxies',
634
            'orm.em.options' => $options,
635
            'orm.custom.functions.string' => array(
636
                'NORMALIZE' => 'Eccube\Doctrine\ORM\Query\Normalize',
637
            ),
638
            'orm.custom.functions.numeric' => array(
639
                'EXTRACT' => 'Eccube\Doctrine\ORM\Query\Extract',
640
            ),
641
        ));
642
643
        $this->extend('orm.em', function (\Doctrine\ORM\EntityManager $em, \Silex\Application $app) {
644
            // tax_rule
645
            $taxRuleRepository = $em->getRepository('Eccube\Entity\TaxRule');
646
            $taxRuleRepository->setApplication($app);
647
            $taxRuleService = new \Eccube\Service\TaxRuleService($taxRuleRepository);
648 1179
            $em->getEventManager()->addEventSubscriber(new \Eccube\Doctrine\EventSubscriber\TaxRuleEventSubscriber($taxRuleService));
649 1179
650 1179
            // save
651 1179
            $saveEventSubscriber = new \Eccube\Doctrine\EventSubscriber\SaveEventSubscriber($app);
652
            $em->getEventManager()->addEventSubscriber($saveEventSubscriber);
653
654
            // timezone
655
            $timezoneSubscriber = new \Eccube\Doctrine\EventSubscriber\TimeZoneSubscriber($app);
656
            $em->getEventManager()->addEventSubscriber($timezoneSubscriber);
657
658
            // clear cache
659
            $clearCacheEventSubscriber = new \Eccube\Doctrine\EventSubscriber\ClearCacheEventSubscriber($app);
660
            $em->getEventManager()->addEventSubscriber($clearCacheEventSubscriber);
661 1179
662 1179
            // filters
663 1179
            $config = $em->getConfiguration();
664 1179
            $config->addFilter("soft_delete", '\Eccube\Doctrine\Filter\SoftDeleteFilter');
665
            $config->addFilter("nostock_hidden", '\Eccube\Doctrine\Filter\NoStockHiddenFilter');
666
            $config->addFilter("incomplete_order_status_hidden", '\Eccube\Doctrine\Filter\OrderStatusFilter');
667 1179
            $em->getFilters()->enable('soft_delete');
668 1179
669
            return $em;
670
        });
671 1179
672 1179
        if (!$this['debug']) {
673
            // second level cacheの設定.
674
            $this->extend(
675 1179
                'orm.em.config',
676 1179
                function (\Doctrine\ORM\Configuration $config, \Silex\Application $app) {
677 1179
                    $config->setSecondLevelCacheEnabled();
678 1179
                    $cacheConfig = $config->getSecondLevelCacheConfiguration();
679 1179
                    $regionConfig = $cacheConfig->getRegionsConfiguration();
680
                    // TODO キャッシュ先は設定で切り替えられるように
681 1179
                    $cache = $this['orm.cache.factory'](
682 1179
                        'filesystem',
683
                        [
684
                            'path' => __DIR__.'/../../app/cache/doctrine/second'
685
                        ]
686 1179
                    );
687
                    $factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($regionConfig, $cache);
688 1179
                    $cacheConfig->setCacheFactory($factory);
689 1179
690 1179
                    return $config;
691
                }
692 1179
            );
693
        }
694 1179
    }
695
696 1179
    public function initSecurity()
697 1179
    {
698 1179
        $this->register(new \Silex\Provider\SecurityServiceProvider());
699 1179
        $this->register(new \Silex\Provider\CsrfServiceProvider());
700
        $this->register(new \Silex\Provider\RememberMeServiceProvider());
701
702
        $this['security.firewalls'] = array(
703
            'admin' => array(
704 1179
                'pattern' => "^/{$this['config']['admin_route']}/",
705 1179
                'form' => array(
706
                    'login_path' => "/{$this['config']['admin_route']}/login",
707 1179
                    'check_path' => "/{$this['config']['admin_route']}/login_check",
708
                    'username_parameter' => 'login_id',
709 1179
                    'password_parameter' => 'password',
710
                    'with_csrf' => true,
711 1179
                    'use_forward' => true,
712
                ),
713
                'logout' => array(
714
                    'logout_path' => "/{$this['config']['admin_route']}/logout",
715
                    'target_url' => "/{$this['config']['admin_route']}/",
716
                ),
717
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Member'),
718
                'anonymous' => true,
719
            ),
720
            'customer' => array(
721
                'pattern' => '^/',
722
                'form' => array(
723
                    'login_path' => '/mypage/login',
724
                    'check_path' => '/login_check',
725 1179
                    'username_parameter' => 'login_email',
726 1179
                    'password_parameter' => 'login_pass',
727
                    'with_csrf' => true,
728
                    'use_forward' => true,
729 1179
                ),
730 1179
                'logout' => array(
731
                    'logout_path' => '/logout',
732
                    'target_url' => '/',
733 1179
                ),
734
                'remember_me' => array(
735 1179
                    'key' => sha1($this['config']['auth_magic']),
736
                    'name' => $this['config']['cookie_name'].'_rememberme',
737
                    // lifetimeはデフォルトの1年間にする
738
                    // 'lifetime' => $this['config']['cookie_lifetime'],
739
                    'path' => $this['config']['root_urlpath'] ?: '/',
740 1179
                    'secure' => $this['config']['force_ssl'],
741 1179
                    'httponly' => true,
742 1179
                    'always_remember_me' => false,
743
                    'remember_me_parameter' => 'login_memory',
744
                ),
745
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Customer'),
746
                'anonymous' => true,
747
            ),
748
        );
749
750 1175
        $channel = null;
751
        // 強制SSL
752
        if ($this['config']['force_ssl'] == \Eccube\Common\Constant::ENABLED) {
753 1175
            $channel = "https";
754 1175
        }
755 1175
756
        $this['security.access_rules'] = array(
757
            array("^/{$this['config']['admin_route']}/login", 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
758
            array("^/{$this['config']['admin_route']}/", 'ROLE_ADMIN', $channel),
759 1179
            array('^/mypage/login', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
760
            array('^/mypage/withdraw_complete', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
761
            array('^/mypage/change', 'IS_AUTHENTICATED_FULLY', $channel),
762
            array('^/mypage', 'ROLE_USER', $channel),
763
        );
764 1175
765
        $this['eccube.password_encoder'] = function ($app) {
766
            return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
767
        };
768 1175
        $this['security.encoder_factory'] = function ($app) {
769
            return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
770 1175
                'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
771 1179
                'Eccube\Entity\Member' => $app['eccube.password_encoder'],
772
            ));
773
        };
774 1175
        $this['eccube.event_listner.security'] = function ($app) {
775
            return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
776
        };
777 1179
778
        // Voterの設定
779
        $this['authority_voter'] = function ($app) {
780 1175
            return new \Eccube\Security\Voter\AuthorityVoter($app);
781
        };
782 1175
783
        $this->extend('security.voters', function ($voters, \Silex\Application $app) {
784
            $voters[] = $app['authority_voter'];
785 1175
786 1175
            return $voters;
787
        });
788
789
        $this['security.access_manager'] = function ($app) {
790
            return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
791
        };
792
793
        $this->on(\Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN, array($this['eccube.event_listner.security'], 'onInteractiveLogin'));
794 1169
    }
795
796 1169
    /**
797
     * ロードバランサー、プロキシサーバの設定を行う
798
     */
799
    public function initProxy()
800
    {
801
        $config = $this['config'];
802
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
803
            $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($config) {
804 475
                // サブリクエストのREMOTE_ADDRも動的に設定を行う必要があるため、KernelEvents::REQUESTを使用する
805
                Request::setTrustedProxies(array_merge(array($event->getRequest()->server->get('REMOTE_ADDR')), $config['trusted_proxies']));
806 475
            }, self::EARLY_EVENT);
807 View Code Duplication
        } elseif (isset($config['trusted_proxies']) && !empty($config['trusted_proxies'])) {
808
            Request::setTrustedProxies($config['trusted_proxies']);
809
        }
810
    }
811
812
    public function initializePlugin()
813
    {
814
        if ($this->initializedPlugin) {
815
            return;
816
        }
817
        $this->register(new ServiceProvider\EccubePluginServiceProvider());
818
        $this->initializedPlugin = true;
819 1179
    }
820
821 1179
    /**
822 1179
     * PHPUnit を実行中かどうかを設定する.
823
     *
824
     * @param boolean $testMode PHPUnit を実行中の場合 true
825
     */
826
    public function setTestMode($testMode)
827
    {
828
        $this->testMode = $testMode;
829
    }
830
831
    /**
832
     * PHPUnit を実行中かどうか.
833
     *
834
     * @return boolean PHPUnit を実行中の場合 true
835
     */
836
    public function isTestMode()
837
    {
838
        return $this->testMode;
839
    }
840
841
    /**
842
     *
843
     * データベースの接続を確認
844
     * 成功 : trueを返却
845
     * 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
846
     * 備考 : app['debug']がtrueの際は処理を行わない
847
     *
848
     * @return boolean true
849
     *
850
     */
851
    protected function checkDatabaseConnection()
852
    {
853
        if ($this['debug']) {
854
            return;
855
        }
856
        try {
857 1179
            $this['db']->connect();
858
        } catch (\Doctrine\DBAL\DBALException $e) {
859 1179
            $this['monolog']->error($e->getMessage());
860 1179
            $this['twig.path'] = array(__DIR__.'/Resource/template/exception');
861 1179
            $html = $this['twig']->render('error.twig', array(
862 1179
                'error_title' => 'データーベース接続エラー',
863 1179
                'error_message' => 'データーベースを確認してください',
864 1179
            ));
865 1179
            $response = new Response();
866 1179
            $response->setContent($html);
867 1179
            $response->setStatusCode('500');
868 1179
            $response->headers->set('Content-Type', 'text/html');
869 1179
            $response->send();
870
            die();
871
        }
872
873
        return true;
874
    }
875
876 1179
    /**
877 1179
     * Config ファイルをパースし、連想配列を返します.
878 1179
     *
879 1179
     * $config_name.yml ファイルをパースし、連想配列を返します.
880 1179
     * $config_name.php が存在する場合は、 PHP ファイルに記述された連想配列を使用します。
881 1179
     *
882 1179
     * @param string $config_name Config 名称
883 1179
     * @param array $configAll Config の連想配列
884
     * @param boolean $wrap_key Config の連想配列に config_name のキーを生成する場合 true, デフォルト false
885
     * @param string $ymlPath config yaml を格納したディレクトリ
886
     * @param string $distPath config yaml dist を格納したディレクトリ
887
     * @return Application
888
     */
889
    public function parseConfig($config_name, array &$configAll, $wrap_key = false, $ymlPath = null, $distPath = null)
890 1179
    {
891 1179
        $ymlPath = $ymlPath ? $ymlPath : __DIR__.'/../../app/config/eccube';
892
        $distPath = $distPath ? $distPath : __DIR__.'/../../src/Eccube/Resource/config';
893 1179
        $config = array();
894
        $config_php = $ymlPath.'/'.$config_name.'.php';
895
        if (!file_exists($config_php)) {
896 1179
            $config_yml = $ymlPath.'/'.$config_name.'.yml';
897
            if (file_exists($config_yml)) {
898
                $config = Yaml::parse(file_get_contents($config_yml));
899
                $config = empty($config) ? array() : $config;
900 View Code Duplication
                if (isset($this['output_config_php']) && $this['output_config_php']) {
901
                    file_put_contents($config_php, sprintf('<?php return %s', var_export($config, true)).';');
902
                }
903
            }
904
        } else {
905 1179
            $config = require $config_php;
906
        }
907 1179
908 1179
        // `%ROOT_DIR%`を絶対パスに変換
909 1179
        $rootDir = realpath(__DIR__.'/../../');
910
        array_walk($config, function(&$value) use ($rootDir) {
911
            $value = str_replace('%ROOT_DIR%', $rootDir, $value);
912
        });
913
914
        $config_dist = array();
915
        $config_php_dist = $distPath.'/'.$config_name.'.dist.php';
916
        if (!file_exists($config_php_dist)) {
917
            $config_yml_dist = $distPath.'/'.$config_name.'.yml.dist';
918
            if (file_exists($config_yml_dist)) {
919
                $config_dist = Yaml::parse(file_get_contents($config_yml_dist));
920 View Code Duplication
                if (isset($this['output_config_php']) && $this['output_config_php']) {
921 1179
                    file_put_contents($config_php_dist, sprintf('<?php return %s', var_export($config_dist, true)).';');
922
                }
923
            }
924 1179
        } else {
925 1179
            $config_dist = require $config_php_dist;
926
        }
927
928
        if ($wrap_key) {
929
            $configAll = array_replace_recursive($configAll, array($config_name => $config_dist), array($config_name => $config));
930
        } else {
931
            $configAll = array_replace_recursive($configAll, $config_dist, $config);
932
        }
933
934
        return $this;
935
    }
936
937
    /**
938
     * セッションが開始されているかどうか.
939
     *
940
     * @return boolean セッションが開始済みの場合 true
941
     * @link http://php.net/manual/ja/function.session-status.php#113468
942
     */
943
    protected function isSessionStarted()
944
    {
945
        if (php_sapi_name() !== 'cli') {
946
            if (version_compare(phpversion(), '5.4.0', '>=')) {
947
                return session_status() === PHP_SESSION_ACTIVE ? true : false;
948
            } else {
949
                return session_id() === '' ? false : true;
950
            }
951
        }
952
953
        return false;
954
    }
955
956
    /**
957
     * Http Cache対応
958
     */
959
    protected function initCacheRequest()
960
    {
961
        // httpキャッシュが無効の場合はイベント設定を行わない.
962
        if (!$this['config']['http_cache']['enabled']) {
963
            return;
964
        }
965
966
        $app = $this;
967
968
        // Response Event(http cache対応、event実行は一番遅く設定)
969
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
970
971
            if (!$event->isMasterRequest()) {
972
                return;
973
            }
974
975
            $request = $event->getRequest();
976
            $response = $event->getResponse();
977
978
            $route = $request->attributes->get('_route');
979
980
            $etag = md5($response->getContent());
981
982
            if (strpos($route, 'admin') === 0) {
983
                // 管理画面
984
985
                // 管理画面ではコンテンツの中身が変更された時点でキャッシュを更新し、キャッシュの適用範囲はprivateに設定
986
                $response->setCache(array(
987
                    'etag' => $etag,
988
                    'private' => true,
989
                ));
990
991
                if ($response->isNotModified($request)) {
992
                    return $response;
993
                }
994
995
            } else {
996
                // フロント画面
997
                $cacheRoute = $app['config']['http_cache']['route'];
998
999
                if (in_array($route, $cacheRoute) === true) {
1000
                    // キャッシュ対象となる画面lが含まれていた場合、キャッシュ化
1001
                    // max-ageを設定しているためExpiresは不要
1002
                    // Last-Modifiedだと比較する項目がないためETagで対応
1003
                    // max-ageを設定していた場合、contentの中身が変更されても変更されない
1004
1005
                    $age = $app['config']['http_cache']['age'];
1006
1007
                    $response->setCache(array(
1008
                        'etag' => $etag,
1009
                        'max_age' => $age,
1010
                        's_maxage' => $age,
1011
                        'public' => true,
1012
                    ));
1013
1014
                    if ($response->isNotModified($request)) {
1015
                        return $response;
1016
                    }
1017
                }
1018
            }
1019
1020
        }, -1024);
1021
    }
1022
}
1023