Completed
Push — dev ( 19c9e2...7c72bd )
by James Ekow Abaka
22:29 queued 21:18
created

SqliteDescriptor   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 155
Duplicated Lines 4.52 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 97.65%

Importance

Changes 0
Metric Value
wmc 25
lcom 1
cbo 1
dl 7
loc 155
ccs 83
cts 85
cp 0.9765
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getColumns() 0 16 3
A cleanDefaultValue() 0 8 2
A getForeignKeys() 0 20 2
A extractIndexDetails() 0 12 3
A getIndexDetails() 0 15 3
A getIndices() 0 4 1
A getPrimaryKey() 0 20 3
A getSchemata() 0 4 1
A getTables() 7 25 3
A getUniqueKeys() 0 4 1
A getViews() 0 4 1
A hasAutoIncrementingKey() 0 9 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/*
4
 * The MIT License
5
 *
6
 * Copyright 2014-2018 James Ekow Abaka Ainooson
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 */
26
27
namespace ntentan\atiaa\descriptors;
28
29
class SqliteDescriptor extends \ntentan\atiaa\Descriptor
30
{
31 3
    protected function getColumns(&$table)
32
    {
33 3
        $pragmaColumns = $this->driver->query("PRAGMA table_info({$table['name']})");
34 3
        foreach ($pragmaColumns as $column) {
35 3
            preg_match("/(?<type>[a-zA-Z]*)(\((?<length>[0-9]+)\))*/", $column['type'], $matches);
36 3
            $columns[] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$columns was never initialized. Although not strictly required by PHP, it is generally a good practice to add $columns = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
37 3
                'name'    => $column['name'],
38 3
                'type'    => $matches['type'],
39 3
                'nulls'   => $column['notnull'] == '0',
40 3
                'default' => $column['dflt_value'],
41 3
                'length'  => isset($matches['length']) ? $matches['length'] : null,
42
            ];
43
        }
44
45 3
        return $columns;
0 ignored issues
show
Bug introduced by
The variable $columns does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
46
    }
47
48 1
    protected function cleanDefaultValue($default)
49
    {
50 1
        if (preg_match("/(')?(?<value>.*)/", $default, $matches)) {
51 1
            return substr($matches['value'], 0, strlen($matches['value']) - 1);
52
        } else {
53
            return;
54
        }
55
    }
56
57 3
    protected function getForeignKeys(&$table)
58
    {
59 3
        $foreignKeys = [];
60 3
        $pragmaColumns = $this->driver->query("pragma foreign_key_list({$table['name']})");
61 3
        foreach ($pragmaColumns as $i => $foreignKey) {
62 2
            $foreignKeys[] = [
63 2
                'name'           => "{$table['name']}_{$foreignKey['table']}_{$i}_fk",
64 2
                'schema'         => $table['schema'],
65 2
                'table'          => $table['name'],
66 2
                'column'         => $foreignKey['from'],
67 2
                'foreign_table'  => $foreignKey['table'],
68 2
                'foreign_schema' => 'main',
69 2
                'foreign_column' => $foreignKey['to'],
70 2
                'on_update'      => $foreignKey['on_update'],
71 2
                'on_delete'      => $foreignKey['on_delete'],
72
            ];
73
        }
74
75 3
        return $foreignKeys;
76
    }
77
78 2
    private function extractIndexDetails($details, $index, &$indexDetails)
79
    {
80 2
        foreach ($details as $detail) {
81 2
            if ($detail['name'] != '') {
82 2
                $indexDetails[] = [
83 2
                    'column' => $detail['name'],
84 2
                    'name'   => $index['name'],
85 2
                    'schema' => $index['schema'],
86
                ];
87
            }
88
        }
89 2
    }
90
91 3
    private function getIndexDetails($table, $unique)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
92
    {
93 3
        $indices = $this->driver->query("pragma index_list({$table['name']})");
94 3
        $indexDetails = [];
95
96 3
        foreach ($indices as $index) {
97 2
            if ($index['unique'] == $unique) {
98 2
                $index['schema'] = $table['schema'];
99 2
                $detail = $this->driver->query("pragma index_info({$index['name']})");
100 2
                $this->extractIndexDetails($detail, $index, $indexDetails);
101
            }
102
        }
103
104 3
        return $indexDetails;
105
    }
106
107 3
    protected function getIndices(&$table)
108
    {
109 3
        return $this->getIndexDetails($table, '0');
110
    }
111
112 3
    protected function getPrimaryKey(&$table)
113
    {
114 3
        $keyColumns = [];
115 3
        $pragmaColumns = $this->driver->query("PRAGMA table_info({$table['name']})");
116 3
        foreach ($pragmaColumns as $column) {
117 3
            if ($column['pk'] > 0) {
118 2
                $keyColumns[] = [
119 2
                    'order'  => $column['pk'],
120 2
                    'column' => $column['name'],
121 2
                    'name'   => "{$table['name']}_pk",
122
                ];
123
            }
124
        }
125
126
        usort($keyColumns, function ($a, $b) {
127
            return $a['order'] - $b['order'];
128 3
        });
129
130 3
        return $keyColumns;
131
    }
132
133 2
    protected function getSchemata()
134
    {
135 2
        return [['name' => 'main']];
136
    }
137
138 5
    protected function getTables($schema, $tables, $includeViews)
139
    {
140 5 View Code Duplication
        if ($includeViews) {
141 2
            $condition = '(type = ? or type = ?)';
142 2
            $bind = ['table', 'view'];
143
        } else {
144 3
            $condition = 'type = ?';
145 3
            $bind = ['table'];
146
        }
147
148 5
        if (count($tables) > 0) {
149 3
            return $this->driver->quotedQuery(
150
                'select name as "name", \'main\' as "schema" from sqlite_master
151 3
                where '.$condition.' and name not in (\'sqlite_master\', \'sqlite_sequence\') and name in (?'.str_repeat(', ?', count($tables) - 1).')
152
                order by name',
153 3
                array_merge($bind, $tables)
154
            );
155
        } else {
156 2
            return $this->driver->quotedQuery(
157
                'select name as "name", \'main\' as "schema" from sqlite_master
158 2
                where name not in (\'sqlite_master\', \'sqlite_sequence\') and '.$condition,
159 2
                array_merge($bind)
160
            );
161
        }
162
    }
163
164 3
    protected function getUniqueKeys(&$table)
165
    {
166 3
        return $this->getIndexDetails($table, '1');
167
    }
168
169 2
    protected function getViews(&$schema)
170
    {
171 2
        return $this->driver->query("select 'main' as schema, name, sql as definition from sqlite_master where type = 'view'");
172
    }
173
174 3
    protected function hasAutoIncrementingKey(&$table)
175
    {
176 3
        $sql = $this->driver->query('select sql from sqlite_master where name = ?', [$table['name']]);
177 3
        if (preg_match('/AUTOINCREMENT/', $sql[0]['sql'])) {
178 2
            return true;
179
        } else {
180 1
            return false;
181
        }
182
    }
183
}
184