Completed
Pull Request — master (#2)
by James Ekow Abaka
01:27
created

SqliteDescriptor   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 154
Duplicated Lines 4.55 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 97.62%

Importance

Changes 0
Metric Value
wmc 25
c 0
b 0
f 0
lcom 1
cbo 1
dl 7
loc 154
ccs 82
cts 84
cp 0.9762
rs 10

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 getSchemata() 0 4 1
A getTables() 7 23 3
A getUniqueKeys() 0 4 1
A getViews() 0 4 1
A hasAutoIncrementingKey() 0 9 2
A getPrimaryKey() 0 19 3

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
namespace ntentan\atiaa\descriptors;
4
5
class SqliteDescriptor extends \ntentan\atiaa\Descriptor
6
{
7
8 3
    protected function getColumns(&$table)
9
    {
10 3
        $pragmaColumns = $this->driver->query("PRAGMA table_info({$table['name']})");
11 3
        foreach ($pragmaColumns as $column) {
12 3
            preg_match("/(?<type>[a-zA-Z]*)(\((?<length>[0-9]+)\))*/", $column['type'], $matches);
13 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...
14 3
                'name' => $column['name'],
15 3
                'type' => $matches['type'],
16 3
                'nulls' => $column['notnull'] == '0',
17 3
                'default' => $column['dflt_value'],
18 3
                'length' => isset($matches['length']) ? $matches['length'] : null
19
            ];
20
        }
21
22 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...
23
    }
24
25 1
    protected function cleanDefaultValue($default)
26
    {
27 1
        if(preg_match("/(')?(?<value>.*)/", $default, $matches)) {
28 1
            return substr($matches['value'], 0,  strlen($matches['value']) - 1);
29
        } else {
30
            return null;
31
        }
32
    }
33
34 3
    protected function getForeignKeys(&$table)
35
    {
36 3
        $foreignKeys = [];
37 3
        $pragmaColumns = $this->driver->query("pragma foreign_key_list({$table['name']})");
38 3
        foreach ($pragmaColumns as $i => $foreignKey) {
39 2
            $foreignKeys[] = [
40 2
                'name' => "{$table['name']}_{$foreignKey['table']}_{$i}_fk",
41 2
                'schema' => $table['schema'],
42 2
                'table' => $table['name'],
43 2
                'column' => $foreignKey['from'],
44 2
                'foreign_table' => $foreignKey['table'],
45 2
                'foreign_schema' => 'main',
46 2
                'foreign_column' => $foreignKey['to'],
47 2
                'on_update' => $foreignKey['on_update'],
48 2
                'on_delete' => $foreignKey['on_delete']
49
            ];
50
        }
51
52 3
        return $foreignKeys;
53
    }
54
55 2
    private function extractIndexDetails($details, $index, &$indexDetails)
56
    {
57 2
        foreach ($details as $detail) {
58 2
            if ($detail['name'] != '') {
59 2
                $indexDetails[] = [
60 2
                    'column' => $detail['name'],
61 2
                    'name' => $index['name'],
62 2
                    'schema' => $index['schema']
63
                ];
64
            }
65
        }
66 2
    }
67
68 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...
69
    {
70 3
        $indices = $this->driver->query("pragma index_list({$table['name']})");
71 3
        $indexDetails = [];
72
73 3
        foreach ($indices as $index) {
74 2
            if ($index['unique'] == $unique) {
75 2
                $index['schema'] = $table['schema'];
76 2
                $detail = $this->driver->query("pragma index_info({$index['name']})");
77 2
                $this->extractIndexDetails($detail, $index, $indexDetails);
78
            }
79
        }
80
81 3
        return $indexDetails;
82
    }
83
84 3
    protected function getIndices(&$table)
85
    {
86 3
        return $this->getIndexDetails($table, '0');
87
    }
88
89 3
    protected function getPrimaryKey(&$table)
90
    {
91 3
        $keyColumns = [];
92 3
        $pragmaColumns = $this->driver->query("PRAGMA table_info({$table['name']})");
93 3
        foreach ($pragmaColumns as $column) {
94 3
            if ($column['pk'] > 0) {
95 2
                $keyColumns[] = [
96 2
                    'order' => $column['pk'],
97 2
                    'column' => $column['name'],
98 3
                    'name' => "{$table['name']}_pk"
99
                ];
100
            }
101
        }
102
103
        usort($keyColumns, function ($a, $b) {
104
            return $a['order'] - $b['order'];
105 3
        });
106 3
        return $keyColumns;
107
    }
108
109 2
    protected function getSchemata()
110
    {
111 2
        return [['name' => 'main']];
112
    }
113
114 5
    protected function getTables($schema, $tables, $includeViews)
115
    {
116 5 View Code Duplication
        if ($includeViews) {
117 2
            $condition = "(type = ? or type = ?)";
118 2
            $bind = array('table', 'view');
119
        } else {
120 3
            $condition = "type = ?";
121 3
            $bind = array('table');
122
        }
123
124 5
        if (count($tables) > 0) {
125 3
            return $this->driver->quotedQuery(
126
                            'select name as "name", \'main\' as "schema" from sqlite_master
127 3
                where ' . $condition . ' and name not in (\'sqlite_master\', \'sqlite_sequence\') and name in (?' . str_repeat(', ?', count($tables) - 1) . ')
128 3
                order by name', array_merge($bind, $tables)
129
            );
130
        } else {
131 2
            return $this->driver->quotedQuery(
132
                            'select name as "name", \'main\' as "schema" from sqlite_master
133 2
                where name not in (\'sqlite_master\', \'sqlite_sequence\') and ' . $condition, array_merge($bind)
134
            );
135
        }
136
    }
137
138 3
    protected function getUniqueKeys(&$table)
139
    {
140 3
        return $this->getIndexDetails($table, '1');
141
    }
142
143 2
    protected function getViews(&$schema)
144
    {
145 2
        return $this->driver->query("select 'main' as schema, name, sql as definition from sqlite_master where type = 'view'");
146
    }
147
148 3
    protected function hasAutoIncrementingKey(&$table)
149
    {
150 3
        $sql = $this->driver->query("select sql from sqlite_master where name = ?", [$table['name']]);
151 3
        if (preg_match("/AUTOINCREMENT/", $sql[0]['sql'])) {
152 2
            return true;
153
        } else {
154 1
            return false;
155
        }
156
    }
157
158
}
159