Table   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 45
dl 0
loc 197
rs 10
c 5
b 0
f 0
wmc 20

13 Methods

Rating   Name   Duplication   Size   Complexity  
A insert() 0 5 1
A apply() 0 11 2
A __construct() 0 6 2
A update() 0 11 3
A getColumns() 0 3 1
A select() 0 3 1
A getName() 0 3 1
A delete() 0 7 2
A __toString() 0 3 1
A cache() 0 3 1
A setName() 0 8 2
A offsetGet() 0 3 1
A count() 0 7 2
1
<?php
2
3
namespace Helix\DB;
4
5
use Closure;
6
use Helix\DB;
7
use Helix\DB\Fluent\Predicate;
8
9
/**
10
 * Table manipulation using arrays.
11
 *
12
 * Accessing the table as an array produces {@link Column} instances.
13
 *
14
 * @immutable Mutations operate on and return clones.
15
 *
16
 * @method static static factory(DB $db, string $name, array $columns)
17
 */
18
class Table extends AbstractTable
19
{
20
21
    use FactoryTrait;
22
23
    /**
24
     * Prepared statement cache, keyed by function name.
25
     *
26
     * @var Statement[]
27
     */
28
    protected $_cache = [];
29
30
    /**
31
     * `[name => Column]`
32
     *
33
     * @var Column[]
34
     */
35
    protected $columns = [];
36
37
    /**
38
     * @var string
39
     */
40
    protected $name;
41
42
    /**
43
     * @param DB $db
44
     * @param string $name
45
     * @param string[] $columns
46
     */
47
    public function __construct(DB $db, string $name, array $columns)
48
    {
49
        parent::__construct($db);
50
        $this->name = $name;
51
        foreach ($columns as $column) {
52
            $this->columns[$column] = Column::factory($db, $column, $this);
53
        }
54
    }
55
56
    /**
57
     * Returns the table name.
58
     *
59
     * @return string
60
     */
61
    final public function __toString()
62
    {
63
        return $this->name;
64
    }
65
66
    /**
67
     * `INSERT IGNORE`
68
     *
69
     * @param array $values
70
     * @return int Rows affected.
71
     */
72
    public function apply(array $values): int
73
    {
74
        $columns = implode(',', array_keys($values));
75
        $values = $this->db->quoteList($values);
76
        if ($this->db->isSQLite()) {
77
            return $this->db->exec(
78
                "INSERT OR IGNORE INTO {$this} ({$columns}) VALUES ({$values})"
79
            );
80
        }
81
        return $this->db->exec(
82
            "INSERT IGNORE INTO {$this} ({$columns}) VALUES ({$values})"
83
        );
84
    }
85
86
    /**
87
     * Caches a prepared statement.
88
     *
89
     * @param string $key
90
     * @param Closure $prepare `():Statement`
91
     * @return Statement
92
     */
93
    protected function cache(string $key, Closure $prepare)
94
    {
95
        return $this->_cache[$key] ??= $prepare->__invoke();
96
    }
97
98
    /**
99
     * @param array $match `[a => b]`
100
     * @return int
101
     */
102
    public function count(array $match = [])
103
    {
104
        $select = $this->select(['COUNT(*)']);
105
        foreach ($match as $a => $b) {
106
            $select->where(Predicate::match($this->db, $this[$a] ?? $a, $b));
107
        }
108
        return (int)$select->execute()->fetchColumn();
109
    }
110
111
    /**
112
     * Executes a deletion using arbitrary columns.
113
     *
114
     * @see Predicate::match()
115
     *
116
     * @param array $match
117
     * @return int Rows affected.
118
     */
119
    public function delete(array $match): int
120
    {
121
        foreach ($match as $a => $b) {
122
            $match[$a] = Predicate::match($this->db, $this[$a] ?? $a, $b);
123
        }
124
        $match = implode(' AND ', $match);
125
        return $this->db->exec("DELETE FROM {$this} WHERE {$match}");
126
    }
127
128
    /**
129
     * @return Column[]
130
     */
131
    public function getColumns()
132
    {
133
        return $this->columns;
134
    }
135
136
    /**
137
     * @return string
138
     */
139
    final public function getName(): string
140
    {
141
        return $this->name;
142
    }
143
144
    /**
145
     * Executes an insertion using arbitrary columns.
146
     *
147
     * @param array $values
148
     * @return Statement
149
     */
150
    public function insert(array $values)
151
    {
152
        $columns = implode(',', array_keys($values));
153
        $values = $this->db->quoteList($values);
154
        return $this->db->query("INSERT INTO {$this} ($columns) VALUES ($values)");
155
    }
156
157
    /**
158
     * @param string $column
159
     * @return Column
160
     */
161
    public function offsetGet($column)
162
    {
163
        return $this->columns[$column] ?? null;
164
    }
165
166
    /**
167
     * Returns a selection object for columns or expressions in the table.
168
     *
169
     * @param string|string[] $expressions
170
     * @return Select|array[]
171
     */
172
    public function select($expressions = ['*'])
173
    {
174
        return Select::factory($this->db, $this, $expressions);
175
    }
176
177
    /**
178
     * Returns an aliased clone for joins. Columns are also re-qualified.
179
     *
180
     * If you want to rename the table in the schema, use {@link Schema::renameTable()}
181
     *
182
     * @param string $name
183
     * @return Table
184
     */
185
    public function setName(string $name)
186
    {
187
        $clone = clone $this;
188
        $clone->name = $name;
189
        foreach ($this->columns as $name => $column) {
190
            $clone->columns[$name] = $column->setQualifier($clone);
191
        }
192
        return $clone;
193
    }
194
195
    /**
196
     * Executes an update using arbitrary columns.
197
     *
198
     * @see Predicate::match()
199
     *
200
     * @param array $values
201
     * @param array $match
202
     * @return int Rows affected.
203
     */
204
    public function update(array $values, array $match): int
205
    {
206
        foreach ($this->db->quoteArray($values) as $key => $value) {
207
            $values[$key] = "{$key} = {$value}";
208
        }
209
        $values = implode(', ', $values);
210
        foreach ($match as $a => $b) {
211
            $match[$a] = Predicate::match($this->db, $this[$a] ?? $a, $b);
212
        }
213
        $match = implode(' AND ', $match);
214
        return $this->db->exec("UPDATE {$this} SET {$values} WHERE {$match}");
215
    }
216
}
217