Completed
Push — master ( 23bdf1...5ebfb1 )
by Alberto
18s queued 12s
created

Application::addPluginDev()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 9
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2019 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
namespace App;
14
15
use App\Middleware\ProjectMiddleware;
16
use BEdita\I18n\Middleware\I18nMiddleware;
17
use BEdita\WebTools\BaseApplication;
18
use Cake\Core\Configure;
19
use Cake\Core\Configure\Engine\PhpConfig;
20
use Cake\Error\Middleware\ErrorHandlerMiddleware;
21
use Cake\Http\MiddlewareQueue;
22
use Cake\Http\Middleware\CsrfProtectionMiddleware;
23
use Cake\Routing\Middleware\AssetMiddleware;
24
use Cake\Routing\Middleware\RoutingMiddleware;
25
26
/**
27
 * Application class.
28
 */
29
class Application extends BaseApplication
30
{
31
    /**
32
     * Default plugin options
33
     *
34
     * @var array
35
     */
36
    const PLUGIN_DEFAULTS = [
37
        'debugOnly' => false,
38
        'autoload' => false,
39
        'bootstrap' => true,
40
        'routes' => true,
41
        'ignoreMissing' => true,
42
    ];
43
44
    /**
45
     * {@inheritDoc}
46
     */
47
    public function bootstrap()
48
    {
49
        parent::bootstrap();
50
        $this->addPlugin('BEdita/WebTools', ['bootstrap' => true]);
51
    }
52
53
    /**
54
     * @return void
55
     */
56
    protected function bootstrapCli()
57
    {
58
        parent::bootstrapCli();
59
        $this->addPluginDev('IdeHelper');
60
        $this->addPlugin('BEdita/I18n');
61
    }
62
63
    /**
64
     * Add plugin considered as a dev dependency.
65
     * It could be missing in production env.
66
     *
67
     * @param string $name The plugin name
68
     * @return bool
69
     */
70
    public function addPluginDev(string $name): bool
71
    {
72
        try {
73
            $this->addPlugin($name);
74
        } catch (\Exception $e) {
75
            return false;
76
        }
77
78
        return true;
79
    }
80
81
    /**
82
     * Load plugins from 'Plugins' configuration.
83
     * This method will be invoked by `ProjectMiddleware`.
84
     * Should not be invoked in `bootstrap`, to avoid duplicate plugin bootstratp calls.
85
     *
86
     * @return void
87
     */
88
    public function loadPluginsFromConfig(): void
89
    {
90
        $plugins = (array)Configure::read('Plugins');
91
        foreach ($plugins as $plugin => $options) {
92
            $options = array_merge(self::PLUGIN_DEFAULTS, $options);
93
            if (!$options['debugOnly'] || ($options['debugOnly'] && Configure::read('debug'))) {
94
                $this->addPlugin($plugin, $options);
95
                $this->plugins->get($plugin)->bootstrap($this);
96
            }
97
        }
98
    }
99
100
    /**
101
     * {@inheritDoc}
102
     */
103
    public function middleware($middlewareQueue): MiddlewareQueue
104
    {
105
        $middlewareQueue
106
            // Catch any exceptions in the lower layers,
107
            // and make an error page/response
108
            ->add(new ErrorHandlerMiddleware(null, Configure::read('Error')))
109
110
            // Load current project configuration if `multiproject` instance
111
            // Manager plugins will also be loaded here via `loadPluginsFromConfig()`
112
            ->add(new ProjectMiddleware($this))
113
114
            // Handle plugin/theme assets like CakePHP normally does.
115
            ->add(new AssetMiddleware([
116
                'cacheTime' => Configure::read('Asset.cacheTime'),
117
            ]))
118
119
            // Add I18n middleware.
120
            ->add(new I18nMiddleware([
121
                'cookie' => Configure::read('I18n.cookie'),
122
                'switchLangUrl' => Configure::read('I18n.switchLangUrl'),
123
            ]))
124
125
            // Add routing middleware.
126
            ->add(new RoutingMiddleware($this))
127
128
            // Csrf Middleware
129
            ->add($this->csrfMiddleware());
130
131
        return $middlewareQueue;
132
    }
133
134
    /**
135
     * Get internal Csrf Middleware
136
     *
137
     * @return CsrfProtectionMiddleware
138
     */
139
    protected function csrfMiddleware(): CsrfProtectionMiddleware
140
    {
141
        // Csrf Middleware
142
        $csrf = new CsrfProtectionMiddleware();
143
        // Token check will be skipped when callback returns `true`.
144
        $csrf->whitelistCallback(function ($request) {
145
            $actions = (array)Configure::read(sprintf('CsrfExceptions.%s', $request->getParam('controller')));
146
            // Skip token check for API URLs.
147
            if (in_array($request->getParam('action'), $actions)) {
148
                return true;
149
            }
150
        });
151
152
        return $csrf;
153
    }
154
155
    /**
156
     * Load project configuration if corresponding config file is found
157
     *
158
     * @param string|null $project The project name.
159
     * @param string $projectsPath The project configuration files base path.
160
     * @return void
161
     */
162
    public static function loadProjectConfig(?string $project, string $projectsPath): void
163
    {
164
        if (empty($project)) {
165
            return;
166
        }
167
168
        if (file_exists($projectsPath . $project . '.php')) {
169
            Configure::config('projects', new PhpConfig($projectsPath));
170
            Configure::load($project, 'projects');
171
        }
172
    }
173
}
174