DatabaseSchemaMigrationTrait::createClientsView()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 26

Duplication

Lines 26
Ratio 100 %

Code Coverage

Tests 20
CRAP Score 1

Importance

Changes 0
Metric Value
dl 26
loc 26
ccs 20
cts 20
cp 1
rs 9.504
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php declare(strict_types=1);
2
3
namespace Limoncello\Passport\Adaptors\MySql;
4
5
/**
6
 * Copyright 2015-2019 [email protected]
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
use Doctrine\DBAL\Connection;
22
use Doctrine\DBAL\DBALException;
23
use Limoncello\Passport\Contracts\Entities\DatabaseSchemaInterface;
24
use Limoncello\Passport\Traits\DatabaseSchemaMigrationTrait as BaseDatabaseSchemaMigrationTrait;
25
26
/**
27
 * @package Limoncello\Passport
28
 */
29 View Code Duplication
trait DatabaseSchemaMigrationTrait
0 ignored issues
show
Duplication introduced by
This class seems to be duplicated in 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...
30
{
31
    use BaseDatabaseSchemaMigrationTrait {
32
        BaseDatabaseSchemaMigrationTrait::createDatabaseSchema as createDatabaseTables;
33
        BaseDatabaseSchemaMigrationTrait::removeDatabaseSchema as removeDatabaseTables;
34
    }
35
36
    /**
37
     * @param Connection              $connection
38
     * @param DatabaseSchemaInterface $schema
39
     *
40
     * @throws DBALException
41
     *
42
     * @return void
43
     */
44 2
    protected function createDatabaseSchema(Connection $connection, DatabaseSchemaInterface $schema): void
45
    {
46
        try {
47 2
            $this->createDatabaseTables($connection, $schema);
0 ignored issues
show
Bug introduced by
It seems like createDatabaseTables() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
48 2
            $this->createDatabaseViews($connection, $schema);
49 2
        } catch (DBALException $exception) {
50 2
            if ($connection->isConnected() === true) {
51 2
                $this->removeDatabaseSchema($connection, $schema);
52
            }
53
54 2
            throw $exception;
55
        }
56
    }
57
58
    /**
59
     * @param Connection              $connection
60
     * @param DatabaseSchemaInterface $schema
61
     *
62
     * @return void
63
     *
64
     * @throws DBALException
65
     */
66 2
    protected function removeDatabaseSchema(Connection $connection, DatabaseSchemaInterface $schema): void
67
    {
68 2
        $this->removeDatabaseViews($connection, $schema);
69 2
        $this->removeDatabaseTables($connection, $schema);
0 ignored issues
show
Bug introduced by
It seems like removeDatabaseTables() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
70
    }
71
72
    /**
73
     * @param Connection              $connection
74
     * @param DatabaseSchemaInterface $schema
75
     *
76
     * @return void
77
     *
78
     * @throws DBALException
79
     */
80 2
    protected function createDatabaseViews(Connection $connection, DatabaseSchemaInterface $schema): void
81
    {
82 2
        $this->createClientsView($connection, $schema);
83 1
        $this->createTokensView($connection, $schema);
84 1
        $this->createUsersView($connection, $schema);
85 1
        $this->createPassportView($connection, $schema);
86
    }
87
88
    /**
89
     * @param Connection              $connection
90
     * @param DatabaseSchemaInterface $schema
91
     *
92
     * @return void
93
     *
94
     * @throws DBALException
95
     */
96 2
    protected function removeDatabaseViews(Connection $connection, DatabaseSchemaInterface $schema): void
97
    {
98 2
        $this->removePassportView($connection, $schema);
99 2
        $this->removeUsersView($connection, $schema);
100 2
        $this->removeTokensView($connection, $schema);
101 2
        $this->removeClientsView($connection, $schema);
102
    }
103
104
    /** @noinspection PhpUnusedPrivateMethodInspection
105
     * @param Connection              $connection
106
     * @param DatabaseSchemaInterface $schema
107
     *
108
     * @throws DBALException
109
     *
110
     * @return void
111
     */
112 1
    private function createTokensView(Connection $connection, DatabaseSchemaInterface $schema): void
113
    {
114 1
        $view                = $schema->getTokensView();
115 1
        $tokens              = $schema->getTokensTable();
116 1
        $intermediate        = $schema->getTokensScopesTable();
117 1
        $tokensTokenId       = $schema->getTokensIdentityColumn();
118 1
        $intermediateTokenId = $schema->getTokensScopesTokenIdentityColumn();
119 1
        $intermediateScopeId = $schema->getTokensScopesScopeIdentityColumn();
120 1
        $scopes              = $schema->getTokensViewScopesColumn();
121
122
        $sql = <<< EOT
123 1
CREATE OR REPLACE VIEW {$view} AS
124
    SELECT
125
      t.*,
126 1
      GROUP_CONCAT(DISTINCT s.{$intermediateScopeId} ORDER BY s.{$intermediateScopeId} ASC SEPARATOR ' ') AS {$scopes}
127 1
    FROM {$tokens} AS t
128 1
      LEFT JOIN {$intermediate} AS s ON t.{$tokensTokenId} = s.{$intermediateTokenId}
129 1
    GROUP BY t.{$tokensTokenId};
130
EOT;
131 1
        $connection->exec($sql);
132
    }
133
134
    /** @noinspection PhpUnusedPrivateMethodInspection
135
     * @param Connection              $connection
136
     * @param DatabaseSchemaInterface $schema
137
     *
138
     * @throws DBALException
139
     *
140
     * @return void
141
     */
142 2
    private function removeTokensView(Connection $connection, DatabaseSchemaInterface $schema)
143
    {
144 2
        $view = $schema->getTokensView();
145 2
        $sql  = "DROP VIEW IF EXISTS {$view}";
146 2
        $connection->exec($sql);
147
    }
148
149
    /** @noinspection PhpUnusedPrivateMethodInspection
150
     * @param Connection              $connection
151
     * @param DatabaseSchemaInterface $schema
152
     *
153
     * @throws DBALException
154
     *
155
     * @return void
156
     */
157 1
    private function createPassportView(Connection $connection, DatabaseSchemaInterface $schema): void
158
    {
159 1
        $tokensView   = $schema->getTokensView();
160 1
        $view         = $schema->getPassportView();
161 1
        $users        = $schema->getUsersTable();
162 1
        $tokensUserFk = $schema->getTokensUserIdentityColumn();
163
164
        $sql = <<< EOT
165 1
CREATE OR REPLACE VIEW {$view} AS
166
    SELECT *
167 1
    FROM $tokensView
168 1
      LEFT JOIN $users USING ($tokensUserFk);
169
EOT;
170 1
        $connection->exec($sql);
171
    }
172
173
    /** @noinspection PhpUnusedPrivateMethodInspection
174
     * @param Connection              $connection
175
     * @param DatabaseSchemaInterface $schema
176
     *
177
     * @throws DBALException
178
     *
179
     * @return void
180
     */
181 2
    private function removePassportView(Connection $connection, DatabaseSchemaInterface $schema): void
182
    {
183 2
        $view = $schema->getPassportView();
184 2
        $sql  = "DROP VIEW IF EXISTS {$view}";
185 2
        $connection->exec($sql);
186
    }
187
188
    /** @noinspection PhpUnusedPrivateMethodInspection
189
     * @param Connection              $connection
190
     * @param DatabaseSchemaInterface $schema
191
     *
192
     * @throws DBALException
193
     *
194
     * @return void
195
     */
196 2
    private function createClientsView(Connection $connection, DatabaseSchemaInterface $schema)
197
    {
198 2
        $view             = $schema->getClientsView();
199 2
        $scopes           = $schema->getClientsViewScopesColumn();
200 2
        $redirectUris     = $schema->getClientsViewRedirectUrisColumn();
201 2
        $clientsScopes    = $schema->getClientsScopesTable();
202 2
        $clientsUris      = $schema->getRedirectUrisTable();
203 2
        $clients          = $schema->getClientsTable();
204 2
        $clientsClientId  = $schema->getClientsIdentityColumn();
205 2
        $clScopesClientId = $schema->getClientsScopesClientIdentityColumn();
206 2
        $clUrisClientId   = $schema->getRedirectUrisClientIdentityColumn();
207 2
        $urisValue        = $schema->getRedirectUrisValueColumn();
208 2
        $scopesScopeId    = $schema->getScopesIdentityColumn();
209
        $sql              = <<< EOT
210 2
CREATE VIEW {$view} AS
211
    SELECT
212
      c.*,
213 2
      GROUP_CONCAT(DISTINCT s.{$scopesScopeId} ORDER BY s.{$scopesScopeId} ASC SEPARATOR ' ') AS {$scopes},
214 2
      GROUP_CONCAT(DISTINCT u.{$urisValue}     ORDER BY u.{$urisValue} ASC SEPARATOR ' ')     AS {$redirectUris}
215 2
    FROM {$clients} AS c
216 2
      LEFT JOIN {$clientsScopes} AS s ON c.{$clientsClientId} = s.{$clScopesClientId}
217 2
      LEFT JOIN {$clientsUris}   AS u ON c.{$clientsClientId} = u.{$clUrisClientId}
218 2
    GROUP BY c.{$clientsClientId};
219
EOT;
220 2
        $connection->exec($sql);
221
    }
222
223
    /** @noinspection PhpUnusedPrivateMethodInspection
224
     * @param Connection              $connection
225
     * @param DatabaseSchemaInterface $schema
226
     *
227
     * @throws DBALException
228
     *
229
     * @return void
230
     */
231 2
    private function removeClientsView(Connection $connection, DatabaseSchemaInterface $schema)
232
    {
233 2
        $view = $schema->getClientsView();
234 2
        $sql  = "DROP VIEW IF EXISTS {$view}";
235 2
        $connection->exec($sql);
236
    }
237
238
    /** @noinspection PhpUnusedPrivateMethodInspection
239
     * @param Connection              $connection
240
     * @param DatabaseSchemaInterface $schema
241
     *
242
     * @throws DBALException
243
     *
244
     * @return void
245
     */
246 1
    private function createUsersView(Connection $connection, DatabaseSchemaInterface $schema)
247
    {
248 1
        $users = $schema->getUsersTable();
249 1
        if ($users !== null) {
250 1
            $view            = $schema->getUsersView();
251 1
            $tokensValue     = $schema->getTokensValueColumn();
252 1
            $tokensValueAt   = $schema->getTokensValueCreatedAtColumn();
253 1
            $tokensScopes    = $schema->getTokensViewScopesColumn();
254 1
            $tokensView      = $schema->getTokensView();
255 1
            $tokensUserId    = $schema->getTokensUserIdentityColumn();
256 1
            $usersUserId     = $schema->getUsersIdentityColumn();
257 1
            $tokensIsEnabled = $schema->getTokensIsEnabledColumn();
258
259
            $sql = <<< EOT
260 1
CREATE OR REPLACE VIEW {$view} AS
261
    SELECT
262 1
        t.$tokensValue, t.$tokensValueAt, t.$tokensScopes, u.*
263 1
    FROM {$tokensView} AS t
264 1
      LEFT JOIN {$users} AS u ON t.{$tokensUserId} = u.{$usersUserId}
265 1
    WHERE $tokensIsEnabled IS TRUE;
266
EOT;
267 1
            $connection->exec($sql);
268
        }
269
    }
270
271
    /** @noinspection PhpUnusedPrivateMethodInspection
272
     * @param Connection              $connection
273
     * @param DatabaseSchemaInterface $schema
274
     *
275
     * @throws DBALException
276
     *
277
     * @return void
278
     */
279 2
    private function removeUsersView(Connection $connection, DatabaseSchemaInterface $schema)
280
    {
281 2
        $view = $schema->getUsersView();
282 2
        $sql  = "DROP VIEW IF EXISTS {$view}";
283 2
        $connection->exec($sql);
284
    }
285
}
286