Completed
Branch feature/currentUserRefactoring (c13c1d)
by Schlaefer
09:08
created

InstallController::migrate()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 15
nc 5
nop 0
dl 0
loc 27
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Saito - The Threaded Web Forum
7
 *
8
 * @copyright Copyright (c) the Saito Project Developers
9
 * @link https://github.com/Schlaefer/Saito
10
 * @license http://opensource.org/licenses/MIT
11
 */
12
13
namespace Installer\Controller;
14
15
use Cake\Core\Configure;
16
use Cake\Database\Connection;
17
use Cake\Datasource\ConnectionManager;
18
use Cake\Http\Response;
19
use Cake\ORM\TableRegistry;
20
use Cake\Utility\Security;
21
use Installer\Lib\DbVersion;
22
use Installer\Lib\InstallerState;
23
use Psr\Log\LogLevel;
24
25
/**
26
 * Install Controller
27
 */
28
class InstallController extends AppController
29
{
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function initialize()
34
    {
35
        parent::initialize();
36
        $this->loadComponent('Referer');
37
    }
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public function beforeFilter(\Cake\Event\Event $event)
43
    {
44
        $this->set('titleForLayout', __d('installer', 'title'));
45
    }
46
47
    /**
48
     * Starting point
49
     *
50
     * @return \Cake\Http\Response|void
51
     */
52
    public function index()
53
    {
54
        $this->log('Start installer.');
55
        InstallerState::reset();
56
57
        return $this->redirect('/install/dbconnection');
58
    }
59
60
    /**
61
     * Check if connection to DB is working
62
     *
63
     * @return \Cake\Http\Response|void
64
     */
65
    public function dbconnection()
66
    {
67
        try {
68
            /** @var Connection */
69
            $connection = ConnectionManager::get('default');
70
            if ($connection->connect()) {
71
                $this->log('Database connection found.');
72
73
                return $this->installerRedirect('salt');
74
            }
75
        } catch (\Throwable $connectionError) {
76
            // connection manager will throw error if no connection
77
        }
78
79
        $this->log('No database connection.');
80
        $this->set('database', false);
81
    }
82
83
    /**
84
     * Check if security salt is set
85
     *
86
     * @return \Cake\Http\Response|void
87
     */
88
    public function salt()
89
    {
90
        if (!InstallerState::check('salt')) {
91
            return $this->redirect('/');
92
        }
93
94
        $secured = (Security::getSalt() !== '__SALT__')
95
            && (Configure::read('Security.cookieSalt') !== '__SALT__');
96
97
        if ($secured) {
98
            $this->log('Security salt is set.');
99
100
            return $this->installerRedirect('connected');
101
        }
102
103
        $this->log('Security salt is not set.');
104
        $this->set('secured', $secured);
105
    }
106
107
    /**
108
     * Check if there's an existing installation
109
     *
110
     * User uses new software version but hit the Installer accidentally.
111
     *
112
     * @return \Cake\Http\Response|void
113
     */
114
    public function connected()
115
    {
116
        if (!InstallerState::check('connected')) {
117
            return $this->redirect('/');
118
        }
119
120
        try {
121
            (new DbVersion($this->loadModel('Settings')))->get();
122
            $this->log('Installer found Settings-table.');
123
124
            return;
125
        } catch (\Throwable $e) {
126
            // Settings-table doesn't exist yet
127
        }
128
129
        $this->log('Installer didn\'t find Settings-table.');
130
131
        return $this->installerRedirect('migrate');
132
    }
133
134
    /**
135
     * Insert tables and seed data
136
     *
137
     * @return \Cake\Http\Response|void
138
     */
139
    public function migrate()
140
    {
141
        if (!InstallerState::check('migrate')) {
142
            return $this->redirect('/');
143
        }
144
145
        $this->log('Installer checking migration status.');
146
147
        if ($this->getRequest()->is('post')) {
148
            $this->set('tables', false);
149
150
            $this->log('Installer starting initial migrate.');
151
            // Initial layout
152
            $this->migrations->migrate(['target' => 'Saitox5x0x0']);
153
            $this->log('Installer starting seed.');
154
            // The seed is meant for the initial layout
155
            $this->migrations->seed();
156
            $this->log('Installer starting follow-up migrate.');
157
            // Apply migration changes which applies to DB and seed-data (esp. settings-table)
158
            $this->migrations->migrate();
159
        }
160
161
        $status = $this->migrations->status();
162
        if (empty($status[0]) || empty($status[0]['status']) || $status[0]['status'] !== 'down') {
163
            $this->log('Installer migration has run.');
164
165
            return $this->installerRedirect('data');
166
        }
167
    }
168
169
    /**
170
     * Insert data from user-input
171
     *
172
     * @return \Cake\Http\Response|void
173
     */
174
    public function data()
175
    {
176
        if (!InstallerState::check('data')) {
177
            return $this->redirect('/');
178
        }
179
180
        $Users = TableRegistry::getTableLocator()->get('Users');
181
182
        if ($this->getRequest()->is('get')) {
183
            $this->set('admin', $Users->newEntity());
184
185
            return;
186
        }
187
188
        /// setting admin user
189
        $this->log('Installer setting admin user.');
190
        $admin = $Users->get(1);
191
        $data = $this->getRequest()->getData();
192
        $Users->patchEntity($admin, $data);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type null; however, parameter $data of Cake\ORM\Table::patchEntity() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

192
        $Users->patchEntity($admin, /** @scrutinizer ignore-type */ $data);
Loading history...
193
        if (!$Users->save($admin)) {
194
            $this->log('Installer failed saving admin-data.');
195
            $this->set('admin', $admin);
196
197
            return;
198
        }
199
        $this->log('Installer admin-data is saved.');
200
201
        /// setting forum-default email
202
        $this->log('Installer setting forum email.');
203
        $Settings = TableRegistry::getTableLocator()->get('Settings');
204
        $forumEmail = $Settings->findByName('forum_email')->first();
205
        $forumEmail->set('value', $data['user_email']);
206
        $Settings->save($forumEmail);
0 ignored issues
show
Bug introduced by
It seems like $forumEmail can also be of type array and null; however, parameter $entity of Cake\ORM\Table::save() does only seem to accept Cake\Datasource\EntityInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

206
        $Settings->save(/** @scrutinizer ignore-type */ $forumEmail);
Loading history...
207
        $this->log('Installer forum email set.');
208
209
        $this->log('Marking installed.');
210
        (new DbVersion($this->loadModel('Settings')))->set(Configure::read('Saito.v'));
211
212
        return $this->installerRedirect('finished');
213
    }
214
215
    /**
216
     * Installer finished
217
     *
218
     * @return \Cake\Http\Response|void
219
     */
220
    public function finished()
221
    {
222
        if (!InstallerState::check('finished')) {
223
            return $this->redirect('/');
224
        }
225
226
        $this->log('Installer finished.');
227
    }
228
229
    /**
230
     * {@inheritdoc}
231
     */
232
    public function log($msg, $level = LogLevel::INFO, $context = ['saito.install'])
233
    {
234
        parent::log($msg, $level, $context);
235
    }
236
237
    /**
238
     * Redirect to a different installer stage
239
     *
240
     * @param string $action controller-action to redirect to
241
     * @return Response redirect
242
     */
243
    private function installerRedirect(string $action): Response
244
    {
245
        InstallerState::set($action);
246
247
        return $this->redirect('/install/' . $action);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->redirect('/install/' . $action) could return the type null which is incompatible with the type-hinted return Cake\Http\Response. Consider adding an additional type-check to rule them out.
Loading history...
248
    }
249
}
250