StartupController::beforeFilter()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 18
nc 6
nop 1
dl 0
loc 28
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * Licensed under The GPL-3.0 License
4
 * For full copyright and license information, please see the LICENSE.txt
5
 * Redistributions of files must retain the above copyright notice.
6
 *
7
 * @since    2.0.0
8
 * @author   Christopher Castro <[email protected]>
9
 * @link     http://www.quickappscms.org
10
 * @license  http://opensource.org/licenses/gpl-3.0.html GPL-3.0 License
11
 */
12
namespace Installer\Controller;
13
14
use Cake\Controller\Controller;
15
use Cake\Event\Event;
16
use Cake\Filesystem\Folder;
17
use Cake\I18n\I18n;
18
use Cake\Routing\Router;
19
use CMS\Core\Plugin;
20
use Installer\Utility\DatabaseInstaller;
21
use Installer\Utility\ServerTest;
22
23
/**
24
 * Controller for handling new QuickAppsCMS installations.
25
 *
26
 * This controller starts the installation process for a new QuickAppsCMS setup.
27
 *
28
 * @property \User\Model\Table\UsersTable $Users
29
 */
30
class StartupController extends Controller
31
{
32
33
    /**
34
     * {@inheritDoc}
35
     *
36
     * @var string
37
     */
38
    public $components = ['Flash'];
39
40
    /**
41
     * {@inheritDoc}
42
     *
43
     * @param \Cake\Event\Event $event The event that was triggered
44
     * @return void
45
     */
46
    public function beforeFilter(Event $event)
47
    {
48
        if (is_readable(ROOT . '/config/settings.php')) {
49
            $this->redirect('/');
50
        }
51
52
        $this->_prepareLayout();
53
        $this->viewBuilder()
54
            ->className('CMS\View\View')
55
            ->theme(false)
56
            ->layout('Installer.startup')
57
            ->helpers(['Menu.Menu']);
58
59
        if (!empty($this->request->query['locale']) && !in_array($this->request->params['action'], ['language', 'index'])) {
60
            I18n::locale($this->request->query['locale']);
61
            $this->request->session()->write('installation.language', I18n::locale());
62
        } elseif ($this->request->session()->read('installation.language')) {
63
            I18n::locale($this->request->session()->read('installation.language'));
64
        }
65
66
        Router::addUrlFilter(function ($params, $request) {
67
            if (!in_array($request->params['action'], ['language', 'index'])) {
68
                $params['locale'] = I18n::locale();
69
            }
70
71
            return $params;
72
        });
73
    }
74
75
    /**
76
     * Main action.
77
     *
78
     * We redirect to first step of the installation process: `language`.
79
     *
80
     * @return void
81
     */
82
    public function index()
83
    {
84
        $this->redirect([
85
            'plugin' => 'Installer',
86
            'controller' => 'startup',
87
            'action' => 'language'
88
        ]);
89
    }
90
91
    /**
92
     * First step of the installation process.
93
     *
94
     * User must select the language they want to use for the installation process.
95
     *
96
     * @return void
97
     */
98
    public function language()
99
    {
100
        $languages = [
101
            'en_US' => [
102
                'url' => '/installer/startup/requirements?locale=en_US',
103
                'welcome' => 'Welcome to QuickAppsCMS',
104
                'action' => 'Click here to install in English'
105
            ]
106
        ];
107
108
        $Folder = new Folder(Plugin::classPath('Installer') . 'Locale');
109
        foreach ($Folder->read(false, true, true)[0] as $path) {
110
            $code = basename($path);
111
            $file = $path . '/installer.po';
112
113
            if (is_readable($file)) {
114
                I18n::locale($code); // trick for __d()
115
                $languages[$code] = [
116
                    'url' => "/installer/startup/requirements?locale={$code}",
117
                    'welcome' => __d('installer', 'Welcome to QuickAppsCMS'),
118
                    'action' => __d('installer', 'Click here to install in English')
119
                ];
120
            }
121
        }
122
123
        I18n::locale('en_US');
124
        $this->title('Welcome to QuickAppsCMS');
125
        $this->set('languages', $languages);
126
        $this->_step();
127
    }
128
129
    /**
130
     * Second step of the installation process.
131
     *
132
     * We check server requirements here.
133
     *
134
     * @return void
135
     */
136
    public function requirements()
137
    {
138 View Code Duplication
        if (!$this->_step('language')) {
139
            $this->redirect(['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'language']);
140
        }
141
142
        $tests = $this->_getTester();
143
        $errors = $tests->errors();
144
145
        if (empty($errors)) {
146
            $this->_step();
147
        }
148
149
        $this->title(__d('installer', 'Server Requirements'));
150
        $this->set('errors', $errors);
151
    }
152
153
    /**
154
     * Third step of the installation process.
155
     *
156
     * License agreement.
157
     *
158
     * @return void
159
     */
160
    public function license()
161
    {
162 View Code Duplication
        if (!$this->_step('requirements')) {
163
            $this->redirect(['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'requirements']);
164
        }
165
166
        $this->title(__d('installer', 'License Agreement'));
167
        $this->_step();
168
    }
169
170
    /**
171
     * Fourth step of the installation process.
172
     *
173
     * User must introduce database connection information.
174
     *
175
     * @return void
176
     */
177
    public function database()
178
    {
179 View Code Duplication
        if (!$this->_step('license')) {
180
            $this->redirect(['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'license']);
181
        }
182
183
        if (!empty($this->request->data)) {
184
            $dbInstaller = new DatabaseInstaller();
185
            if ($dbInstaller->install($this->request->data())) {
186
                $this->_step();
187
                $this->redirect(['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'account']);
188
            } else {
189
                $errors = '';
190
                foreach ($dbInstaller->errors() as $error) {
191
                    $errors .= "\t<li>{$error}</li>\n";
192
                }
193
                $this->Flash->danger("<ul>\n{$errors}</ul>\n");
194
            }
195
        }
196
197
        $this->title(__d('installer', 'Database Configuration'));
198
    }
199
200
    /**
201
     * Fifth step of the installation process.
202
     *
203
     * Create a new administrator user account.
204
     *
205
     * @return void
206
     */
207
    public function account()
208
    {
209 View Code Duplication
        if (!$this->_step('database')) {
210
            $this->redirect(['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'database']);
211
        }
212
213
        $this->loadModel('User.Users');
214
        $user = $this->Users->newEntity();
215
216
        if ($this->request->data()) {
217
            $data = $this->request->data;
218
            $data['roles'] = ['_ids' => [1]];
219
            $user = $this->Users->newEntity($data);
220
221
            if ($this->Users->save($user)) {
222
                $this->Flash->success(__d('installer', 'Account created you can now login!'));
223
                $this->_step();
224
                $this->redirect(['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'finish']);
225
            } else {
226
                $this->Flash->danger(__d('installer', 'Account could not be created, please check your information.'));
227
            }
228
        }
229
230
        $this->title(__d('installer', 'Create New Account'));
231
        $this->set('user', $user);
232
    }
233
234
    /**
235
     * Last step of the installation process.
236
     *
237
     * Here we say "thanks" and redirect to site's frontend or backend.
238
     *
239
     * @return void
240
     */
241
    public function finish()
242
    {
243
        if ($this->request->data()) {
244
            if (rename(ROOT . '/config/settings.php.tmp', ROOT . '/config/settings.php')) {
245
                snapshot();
246
                $this->request->session()->delete('Startup');
247
248
                if (!empty($this->request->data['home'])) {
249
                    $this->redirect('/');
250
                } else {
251
                    $this->redirect('/admin');
252
                }
253
            } else {
254
                $this->Flash->danger(__d('installer', 'Unable to continue, check write permission for the "/config" directory.'));
255
            }
256
        }
257
258
        $this->title(__d('installer', 'Finish Installation'));
259
    }
260
261
    // @codingStandardsIgnoreStart
262
    /**
263
     * Shortcut for Controller::set('title_for_layout', ...)
264
     *
265
     * @param string $titleForLayout Page's title
266
     * @return void
267
     */
268
    protected function title($titleForLayout)
269
    {
270
        $this->set('title_for_layout', $titleForLayout);
271
    }
272
    // @codingStandardsIgnoreEnd
273
274
    // @codingStandardsIgnoreStart
275
    /**
276
     * Shortcut for Controller::set('description_for_layout', ...)
277
     *
278
     * @param string $descriptionForLayout Page's description
279
     * @return void
280
     */
281
    protected function description($descriptionForLayout)
282
    {
283
        $this->set('description_for_layout', $descriptionForLayout);
284
    }
285
    // @codingStandardsIgnoreEnd
286
287
    /**
288
     * Gets an instance of ServerTest class.
289
     *
290
     * @return \Installer\Utility\ServerTest
291
     */
292
    protected function _getTester()
293
    {
294
        $tests = new ServerTest();
295
        $tests
296
            ->add('php', (bool)version_compare(PHP_VERSION, '5.4.19', '>='), __d('installer', 'Your php version is not supported. check that your version is 5.4.19 or newer.'))
297
            ->add('mbstring', (bool)extension_loaded('mbstring'), __d('installer', 'Missing extension: {0}', 'mbstring'))
298
            ->add('mcrypt', (bool)extension_loaded('mcrypt'), __d('installer', 'Missing extension: {0}', 'mcrypt'))
299
            ->add('iconv', (bool)extension_loaded('iconv'), __d('installer', 'Missing extension: {0}', 'iconv'))
300
            ->add('intl', (bool)extension_loaded('intl'), __d('installer', 'Missing extension: {0}', 'intl'))
301
            ->add('fileinfo', (bool)extension_loaded('fileinfo'), __d('installer', 'Missing extension: {0}', 'fileinfo'))
302
            ->add('tmp_writable', is_writable(TMP), __d('installer', '"{0}" folder is not writable.', 'tmp/'))
303
            ->add('cache_writable', is_writable(TMP . 'cache'), __d('installer', '"{0}" folder is not writable.', 'tmp/cache/'))
304
            ->add('models_writable', is_writable(TMP . 'cache/models'), __d('installer', '"{0}" folder is not writable.', 'tmp/cache/models/'))
305
            ->add('persistent_writable', is_writable(TMP . 'cache/persistent'), __d('installer', '"{0}" folder is not writable.', 'tmp/cache/persistent/'))
306
            ->add('config_writable', is_writable(ROOT . '/config'), __d('installer', '"{0}" folder is not writable.', 'config/'))
307
            ->add('pdo', [
308
                'rule' => function () {
309
                    return
310
                        extension_loaded('pdo') &&
311
                        defined('PDO::ATTR_DEFAULT_FETCH_MODE');
312
                },
313
                'message' => __d('installer', 'Missing extension: {0}', 'PDO'),
314
            ])
315
            ->add('no_safe_mode', [
316
                'rule' => function () {
317
                    return
318
                        ini_get('safe_mode') === false ||
319
                        ini_get('safe_mode') === '' ||
320
                        strtolower(ini_get('safe_mode')) == 'off';
321
                },
322
                'message' => __d('installer', 'Your server has SafeMode on, please turn it off before continuing.'),
323
            ]);
324
325
        return $tests;
326
    }
327
328
    /**
329
     * Check if the given step name was completed. Or marks current step as
330
     * completed.
331
     *
332
     * If $check is set to NULL, it marks current step (controller's action name)
333
     * as completed. If $check is set to a string, it checks if that step was
334
     * completed before.
335
     *
336
     * This allows steps to control user navigation, so users can not pass to the
337
     * next step without completing all previous steps.
338
     *
339
     * @param null|string $check Name of the step to check, or false to mark as
340
     *  completed current step
341
     * @return bool
342
     */
343
    protected function _step($check = null)
344
    {
345
        $_steps = (array)$this->request->session()->read('Startup._steps');
346
        if ($check === null) {
347
            $_steps[] = $this->request->params['action'];
348
            $_steps = array_unique($_steps);
349
            $this->request->session()->write('Startup._steps', $_steps);
350
        } elseif (is_string($check)) {
351
            return in_array($check, $_steps);
352
        }
353
354
        return false;
355
    }
356
357
    /**
358
     * Sets some view-variables used across all steps.
359
     *
360
     * @return void
361
     */
362
    protected function _prepareLayout()
363
    {
364
        $menu = [
365
            __d('installer', 'Welcome') => [
366
                'url' => ['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'language'],
367
                'active' => ($this->request->action === 'language')
368
            ],
369
            __d('installer', 'System Requirements') => [
370
                'url' => ['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'requirements'],
371
                'active' => ($this->request->action === 'requirements')
372
            ],
373
            __d('installer', 'License Agreement') => [
374
                'url' => ['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'license'],
375
                'active' => ($this->request->action === 'license')
376
            ],
377
            __d('installer', 'Database Setup') => [
378
                'url' => ['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'database'],
379
                'active' => ($this->request->action === 'database')
380
            ],
381
            __d('installer', 'Your Account') => [
382
                'url' => ['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'account'],
383
                'active' => ($this->request->action === 'account')
384
            ],
385
            __d('installer', 'Finish') => [
386
                'url' => ['plugin' => 'Installer', 'controller' => 'startup', 'action' => 'finish'],
387
                'active' => ($this->request->action === 'finish')
388
            ],
389
        ];
390
391
        $this->set('menu', $menu);
392
    }
393
}
394