GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

GetTableCommand   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 14
c 1
b 0
f 0
lcom 1
cbo 9
dl 0
loc 133
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setTableName() 0 6 1
A getSql() 0 9 1
B execute() 0 32 6
B loadConstraints() 0 22 5
B getConstraints() 0 30 1
1
<?php
2
namespace Rentgen\Schema\Info;
3
4
use Rentgen\Schema\Command;
5
use Rentgen\Schema\ColumnTypeMapper;
6
use Rentgen\Database\Table;
7
use Rentgen\Database\Column\ColumnCreator;
8
use Rentgen\Database\Constraint\ForeignKey;
9
use Rentgen\Database\Constraint\PrimaryKey;
10
use Rentgen\Database\Constraint\Unique;
11
use Rentgen\Exception\TableNotExistsException;
12
13
/**
14
 * @author Arek Jaskólski <[email protected]>
15
 */
16
class GetTableCommand extends Command
17
{
18
    private $tableName;
19
20
    /**
21
     * Sets a table name.
22
     *
23
     * @param string $tableName A table name.
24
     *
25
     * @return GetTableCommand
26
     */
27
    public function setTableName($tableName)
28
    {
29
        $this->tableName = $tableName;
30
31
        return $this;
32
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function getSql()
38
    {
39
        $sql = sprintf("SELECT table_schema, column_name, data_type, is_identity, is_nullable,
40
            column_default, character_maximum_length, numeric_precision, numeric_scale
41
            FROM information_schema.columns
42
            WHERE table_name ='%s';", $this->tableName);
43
44
        return $sql;
45
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50
    public function execute()
51
    {
52
        $columnTypeMapper = new ColumnTypeMapper();
53
54
        $this->preExecute();
55
        $columns = $this->connection->query($this->getSql());
56
        if (empty($columns)) {
57
            throw new TableNotExistsException($this->tableName);
58
        }
59
        $table = new Table($this->tableName);
60
        if (null === $table->getSchema()) {
61
            $table->setSchema($columns[0]['table_schema']);
62
        }
63
        $columnCreator = new ColumnCreator();
64
        foreach ($columns as $column) {
65
            $columnType = $columnTypeMapper->getCommon($column['data_type']);
66
            $options = array();
67
            $options['not_null'] = $column['is_nullable'] === 'NO';
68
            $options['default'] = $column['column_default'];
69
            if ($columnType === 'string') {
70
                preg_match("/'(.*)'::character varying/", $column['column_default'], $matches);
71
                $options['default'] = isset($matches[1]) ? $matches[1] : '';
72
                $options['limit'] = $column['character_maximum_length'];
73
            }
74
            $column = $columnCreator->create($column['column_name'], $columnType, $options);
75
            $table->addColumn($column);
76
        }
77
        $this->loadConstraints($table);
78
        $this->postExecute();
79
80
        return $table;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $table; (Rentgen\Database\Table) is incompatible with the return type of the parent method Rentgen\Schema\Command::execute of type integer.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
81
    }
82
83
    /**
84
     * Load contsraints to table.
85
     *
86
     * @param Table $table A table.
87
     *
88
     * @return void
89
     */
90
    private function loadConstraints(Table $table)
91
    {
92
93
        foreach ($this->getConstraints() as $constraint) {
94
            switch ($constraint['constraint_type']) {
95
                case 'FOREIGN KEY':
96
                    // TODO Find a better way to define foreign key
97
                    $foreignKey = new ForeignKey(new Table($constraint['table_name']), new Table($constraint['column_name']));
98
                    $foreignKey->setColumns($constraint['references_table']);
99
                    $foreignKey->setReferencedColumns($constraint['references_field']);
100
101
                    $table->addConstraint($foreignKey);
102
                    break;
103
                case 'PRIMARY KEY':
104
                    $table->addConstraint(new PrimaryKey($constraint['column_name'], $table));
105
                    break;
106
                case 'UNIQUE':
107
                    $table->addConstraint(new Unique($constraint['column_name'], new Table($constraint['table_name'])));
108
                    break;
109
            }
110
        }
111
    }
112
113
    /**
114
     * Gets constraints from database.
115
     *
116
     * @return array Array of contraints.
117
     */
118
    private function getConstraints()
119
    {
120
        $sql = sprintf("SELECT tc.constraint_name,
121
            tc.constraint_type,
122
            tc.table_name,
123
            kcu.column_name,
124
            tc.is_deferrable,
125
            tc.initially_deferred,
126
            rc.match_option AS match_type,
127
            rc.update_rule AS on_update,
128
            rc.delete_rule AS on_delete,
129
            ccu.table_name AS references_table,
130
            ccu.column_name AS references_field
131
     FROM information_schema.table_constraints tc
132
LEFT JOIN information_schema.key_column_usage kcu
133
       ON tc.constraint_catalog = kcu.constraint_catalog
134
      AND tc.constraint_schema = kcu.constraint_schema
135
      AND tc.constraint_name = kcu.constraint_name
136
LEFT JOIN information_schema.referential_constraints rc
137
       ON tc.constraint_catalog = rc.constraint_catalog
138
      AND tc.constraint_schema = rc.constraint_schema
139
      AND tc.constraint_name = rc.constraint_name
140
LEFT JOIN information_schema.constraint_column_usage ccu
141
       ON rc.unique_constraint_catalog = ccu.constraint_catalog
142
      AND rc.unique_constraint_schema = ccu.constraint_schema
143
      AND rc.unique_constraint_name = ccu.constraint_name
144
    WHERE tc.table_name = '%s' AND tc.constraint_type IN ('PRIMARY KEY', 'FOREIGN KEY', 'UNIQUE')", $this->tableName);
145
146
        return $this->connection->query($sql);
147
    }
148
}
149