Completed
Branch develop (c2aa4c)
by Anton
05:17
created

PostgresDriver::getPrimary()   C

Complexity

Conditions 8
Paths 12

Size

Total Lines 31
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 31
rs 5.3846
cc 8
eloc 16
nc 12
nop 1
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
namespace Spiral\Database\Drivers\Postgres;
9
10
use Spiral\Core\FactoryInterface;
11
use Spiral\Core\HippocampusInterface;
12
use Spiral\Database\DatabaseInterface;
13
use Spiral\Database\Drivers\Postgres\Schemas\Commander;
14
use Spiral\Database\Drivers\Postgres\Schemas\TableSchema;
15
use Spiral\Database\Entities\Database;
16
use Spiral\Database\Entities\Driver;
17
use Spiral\Database\Exceptions\DriverException;
18
19
/**
20
 * Talks to postgres databases.
21
 */
22
class PostgresDriver extends Driver
23
{
24
    /**
25
     * Driver type.
26
     */
27
    const TYPE = DatabaseInterface::POSTGRES;
28
29
    /**
30
     * Driver schemas.
31
     */
32
    const SCHEMA_TABLE = TableSchema::class;
33
34
    /**
35
     * Commander used to execute commands. :)
36
     */
37
    const COMMANDER = Commander::class;
38
39
    /**
40
     * Query compiler class.
41
     */
42
    const QUERY_COMPILER = QueryCompiler::class;
43
44
    /**
45
     * Default timestamp expression.
46
     */
47
    const TIMESTAMP_NOW = 'now()';
48
49
    /**
50
     * Cached list of primary keys associated with their table names. Used by InsertBuilder to
51
     * emulate last insert id.
52
     *
53
     * @var array
54
     */
55
    private $primaryKeys = [];
56
57
    /**
58
     * Needed to remember table primary keys.
59
     *
60
     * @invisible
61
     * @var HippocampusInterface
62
     */
63
    protected $memory = null;
64
65
    /**
66
     * {@inheritdoc}
67
     * @param string               $name
68
     * @param array                $config
69
     * @param FactoryInterface     $factory
70
     * @param HippocampusInterface $memory
71
     */
72
    public function __construct(
73
        $name,
74
        array $config,
75
        FactoryInterface $factory = null,
76
        HippocampusInterface $memory = null
77
    ) {
78
        parent::__construct($name, $config, $factory);
79
80
        $this->memory = $memory;
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public function hasTable($name)
87
    {
88
        $query = 'SELECT "table_name" FROM "information_schema"."tables" '
89
            . 'WHERE "table_schema" = \'public\' AND "table_type" = \'BASE TABLE\' AND "table_name" = ?';
90
91
        return (bool)$this->query($query, [$name])->fetchColumn();
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97 View Code Duplication
    public function tableNames()
0 ignored issues
show
Duplication introduced by
This method 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...
98
    {
99
        $query = 'SELECT "table_name" FROM "information_schema"."tables" '
100
            . 'WHERE "table_schema" = \'public\' AND "table_type" = \'BASE TABLE\'';
101
102
        $tables = [];
103
        foreach ($this->query($query) as $row) {
104
            $tables[] = $row['table_name'];
105
        }
106
107
        return $tables;
108
    }
109
110
    /**
111
     * Get singular primary key associated with desired table. Used to emulate last insert id.
112
     *
113
     * @param string $table Fully specified table name, including postfix.
114
     * @return string
115
     * @throws DriverException
116
     */
117
    public function getPrimary($table)
118
    {
119
        if (!empty($this->memory) && empty($this->primaryKeys)) {
120
            $this->primaryKeys = $this->memory->loadData($this->getSource() . '-primary');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->memory->loadData(...tSource() . '-primary') can also be of type string or null. However, the property $primaryKeys is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
121
        }
122
123
        if (!empty($this->primaryKeys) && array_key_exists($table, $this->primaryKeys)) {
124
            return $this->primaryKeys[$table];
125
        }
126
127
        if (!$this->hasTable($table)) {
128
            throw new DriverException(
129
                "Unable to fetch table primary key, no such table '{$table}' exists."
130
            );
131
        }
132
133
        $this->primaryKeys[$table] = $this->tableSchema($table)->getPrimaryKeys();
134
        if (count($this->primaryKeys[$table]) === 1) {
135
            //We do support only single primary key
136
            $this->primaryKeys[$table] = $this->primaryKeys[$table][0];
137
        } else {
138
            $this->primaryKeys[$table] = null;
139
        }
140
141
        //Caching
142
        if (!empty($this->memory)) {
143
            $this->memory->saveData($this->getSource() . '-primary', $this->primaryKeys);
144
        }
145
146
        return $this->primaryKeys[$table];
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 View Code Duplication
    public function insertBuilder(Database $database, array $parameters = [])
0 ignored issues
show
Duplication introduced by
This method 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...
153
    {
154
        return $this->factory->make(InsertQuery::class, [
155
                'database' => $database,
156
                'compiler' => $this->queryCompiler($database->getPrefix())
157
            ] + $parameters);
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163
    protected function createPDO()
164
    {
165
        //Spiral is purely UTF-8
166
        $pdo = parent::createPDO();
167
        $pdo->exec("SET NAMES 'UTF-8'");
168
169
        return $pdo;
170
    }
171
}
172