Completed
Push — develop ( 67e5f1...4da4e3 )
by Neomerx
08:20
created

DatabaseSchemaMigrationTrait::createClientsView()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 22

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 8.8571
c 0
b 0
f 0
cc 1
eloc 22
nc 1
nop 2
crap 1
1
<?php namespace Limoncello\Passport\Adaptors\PostgreSql;
2
3
/**
4
 * Copyright 2015-2018 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use Doctrine\DBAL\Connection;
20
use Doctrine\DBAL\DBALException;
21
use Limoncello\Passport\Contracts\Entities\DatabaseSchemaInterface;
22
use Limoncello\Passport\Traits\DatabaseSchemaMigrationTrait as BaseDatabaseSchemaMigrationTrait;
23
24
/**
25
 * @package Limoncello\Passport
26
 */
27 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...
28
{
29
    use BaseDatabaseSchemaMigrationTrait {
30
        BaseDatabaseSchemaMigrationTrait::createDatabaseSchema as createDatabaseTables;
31
        BaseDatabaseSchemaMigrationTrait::removeDatabaseSchema as removeDatabaseTables;
32
    }
33
34
    /**
35
     * @param Connection              $connection
36
     * @param DatabaseSchemaInterface $schema
37
     *
38
     * @throws DBALException
39
     *
40
     * @return void
41
     */
42 1
    protected function createDatabaseSchema(Connection $connection, DatabaseSchemaInterface $schema): void
43
    {
44
        try {
45 1
            $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...
46 1
            $this->createDatabaseViews($connection, $schema);
47 1
        } catch (DBALException $exception) {
48 1
            if ($connection->isConnected() === true) {
49 1
                $this->removeDatabaseSchema($connection, $schema);
50
            }
51
52 1
            throw $exception;
53
        }
54
    }
55
56
    /**
57
     * @param Connection              $connection
58
     * @param DatabaseSchemaInterface $schema
59
     *
60
     * @return void
61
     *
62
     * @throws DBALException
63
     */
64 1
    protected function removeDatabaseSchema(Connection $connection, DatabaseSchemaInterface $schema): void
65
    {
66 1
        $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...
67 1
        $this->removeDatabaseViews($connection, $schema);
68
    }
69
70
    /**
71
     * @param Connection              $connection
72
     * @param DatabaseSchemaInterface $schema
73
     *
74
     * @return void
75
     *
76
     * @throws DBALException
77
     */
78 1
    protected function createDatabaseViews(Connection $connection, DatabaseSchemaInterface $schema): void
79
    {
80 1
        $this->createClientsView($connection, $schema);
81 1
        $this->createTokensView($connection, $schema);
82 1
        $this->createUsersView($connection, $schema);
83 1
        $this->createPassportView($connection, $schema);
84
    }
85
86
    /**
87
     * @param Connection              $connection
88
     * @param DatabaseSchemaInterface $schema
89
     *
90
     * @return void
91
     *
92
     * @throws DBALException
93
     */
94 1
    protected function removeDatabaseViews(Connection $connection, DatabaseSchemaInterface $schema): void
95
    {
96 1
        $this->removePassportView($connection, $schema);
97 1
        $this->removeClientsView($connection, $schema);
98 1
        $this->removeTokensView($connection, $schema);
99 1
        $this->removeUsersView($connection, $schema);
100
    }
101
102
    /**
103
     * @param Connection              $connection
104
     * @param DatabaseSchemaInterface $schema
105
     *
106
     * @throws DBALException
107
     *
108
     * @return void
109
     */
110 1
    private function createTokensView(Connection $connection, DatabaseSchemaInterface $schema): void
111
    {
112 1
        $view                = $schema->getTokensView();
113 1
        $tokens              = $schema->getTokensTable();
114 1
        $intermediate        = $schema->getTokensScopesTable();
115 1
        $tokensTokenId       = $schema->getTokensIdentityColumn();
116 1
        $intermediateTokenId = $schema->getTokensScopesTokenIdentityColumn();
117 1
        $intermediateScopeId = $schema->getTokensScopesScopeIdentityColumn();
118 1
        $scopes              = $schema->getTokensViewScopesColumn();
119
120
        $sql = <<< EOT
121 1
CREATE OR REPLACE VIEW {$view} AS
122
    SELECT
123
      t.*,
124 1
      array_remove(array_agg(s.{$intermediateScopeId}), NULL) AS {$scopes}
125 1
    FROM {$tokens} AS t
126 1
      LEFT JOIN {$intermediate} AS s ON t.{$tokensTokenId} = s.{$intermediateTokenId}
127 1
    GROUP BY t.{$tokensTokenId};
128
EOT;
129 1
        $connection->exec($sql);
130
    }
131
132
    /**
133
     * @param Connection              $connection
134
     * @param DatabaseSchemaInterface $schema
135
     *
136
     * @throws DBALException
137
     *
138
     * @return void
139
     */
140 1
    private function removeTokensView(Connection $connection, DatabaseSchemaInterface $schema)
141
    {
142 1
        $view = $schema->getTokensView();
143 1
        $sql  = "DROP VIEW IF EXISTS {$view}";
144 1
        $connection->exec($sql);
145
    }
146
147
    /**
148
     * @param Connection              $connection
149
     * @param DatabaseSchemaInterface $schema
150
     *
151
     * @throws DBALException
152
     *
153
     * @return void
154
     */
155 1
    private function createPassportView(Connection $connection, DatabaseSchemaInterface $schema): void
156
    {
157 1
        $tokensView   = $schema->getTokensView();
158 1
        $view         = $schema->getPassportView();
159 1
        $users        = $schema->getUsersTable();
160 1
        $tokensUserFk = $schema->getTokensUserIdentityColumn();
161
162
        $sql = <<< EOT
163 1
CREATE OR REPLACE VIEW {$view} AS
164
    SELECT *
165 1
    FROM $tokensView
166 1
      LEFT JOIN $users USING ($tokensUserFk);
167
EOT;
168 1
        $connection->exec($sql);
169
    }
170
171
    /**
172
     * @param Connection              $connection
173
     * @param DatabaseSchemaInterface $schema
174
     *
175
     * @throws DBALException
176
     *
177
     * @return void
178
     */
179 1
    private function removePassportView(Connection $connection, DatabaseSchemaInterface $schema): void
180
    {
181 1
        $view = $schema->getPassportView();
182 1
        $sql  = "DROP VIEW IF EXISTS {$view}";
183 1
        $connection->exec($sql);
184
    }
185
186
    /**
187
     * @param Connection              $connection
188
     * @param DatabaseSchemaInterface $schema
189
     *
190
     * @throws DBALException
191
     *
192
     * @return void
193
     */
194 1
    private function createClientsView(Connection $connection, DatabaseSchemaInterface $schema)
195
    {
196 1
        $view             = $schema->getClientsView();
197 1
        $scopes           = $schema->getClientsViewScopesColumn();
198 1
        $redirectUris     = $schema->getClientsViewRedirectUrisColumn();
199 1
        $clientsScopes    = $schema->getClientsScopesTable();
200 1
        $clientsUris      = $schema->getRedirectUrisTable();
201 1
        $clients          = $schema->getClientsTable();
202 1
        $clientsClientId  = $schema->getClientsIdentityColumn();
203 1
        $clScopesClientId = $schema->getClientsScopesClientIdentityColumn();
204 1
        $clUrisClientId   = $schema->getRedirectUrisClientIdentityColumn();
205 1
        $urisValue        = $schema->getRedirectUrisValueColumn();
206 1
        $scopesScopeId    = $schema->getScopesIdentityColumn();
207
        $sql              = <<< EOT
208 1
CREATE VIEW {$view} AS
209
    SELECT
210
      c.*,
211 1
      array_remove(array_agg(s.{$scopesScopeId}), NULL) AS {$scopes},
212 1
      array_remove(array_agg(u.{$urisValue}), NULL)     AS {$redirectUris}
213 1
    FROM {$clients} AS c
214 1
      LEFT JOIN {$clientsScopes} AS s ON c.{$clientsClientId} = s.{$clScopesClientId}
215 1
      LEFT JOIN {$clientsUris}   AS u ON c.{$clientsClientId} = u.{$clUrisClientId}
216 1
    GROUP BY c.{$clientsClientId};
217
EOT;
218 1
        $connection->exec($sql);
219
    }
220
221
    /**
222
     * @param Connection              $connection
223
     * @param DatabaseSchemaInterface $schema
224
     *
225
     * @throws DBALException
226
     *
227
     * @return void
228
     */
229 1
    private function removeClientsView(Connection $connection, DatabaseSchemaInterface $schema)
230
    {
231 1
        $view = $schema->getClientsView();
232 1
        $sql  = "DROP VIEW IF EXISTS {$view}";
233 1
        $connection->exec($sql);
234
    }
235
236
    /**
237
     * @param Connection              $connection
238
     * @param DatabaseSchemaInterface $schema
239
     *
240
     * @throws DBALException
241
     *
242
     * @return void
243
     */
244 1
    private function createUsersView(Connection $connection, DatabaseSchemaInterface $schema)
245
    {
246 1
        $users = $schema->getUsersTable();
247 1
        if ($users !== null) {
248 1
            $view            = $schema->getUsersView();
249 1
            $tokensValue     = $schema->getTokensValueColumn();
250 1
            $tokensValueAt   = $schema->getTokensValueCreatedAtColumn();
251 1
            $tokensScopes    = $schema->getTokensViewScopesColumn();
252 1
            $tokensView      = $schema->getTokensView();
253 1
            $tokensUserId    = $schema->getTokensUserIdentityColumn();
254 1
            $usersUserId     = $schema->getUsersIdentityColumn();
255 1
            $tokensIsEnabled = $schema->getTokensIsEnabledColumn();
256
257
            $sql = <<< EOT
258 1
CREATE OR REPLACE VIEW {$view} AS
259
    SELECT
260 1
        t.$tokensValue, t.$tokensValueAt, t.$tokensScopes, u.*
261 1
    FROM {$tokensView} AS t
262 1
      LEFT JOIN {$users} AS u ON t.{$tokensUserId} = u.{$usersUserId}
263 1
    WHERE $tokensIsEnabled IS TRUE;
264
EOT;
265 1
            $connection->exec($sql);
266
        }
267
    }
268
269
    /**
270
     * @param Connection              $connection
271
     * @param DatabaseSchemaInterface $schema
272
     *
273
     * @throws DBALException
274
     *
275
     * @return void
276
     */
277 1
    private function removeUsersView(Connection $connection, DatabaseSchemaInterface $schema)
278
    {
279 1
        $view = $schema->getUsersView();
280 1
        $sql  = "DROP VIEW IF EXISTS {$view}";
281 1
        $connection->exec($sql);
282
    }
283
}
284