Passed
Push — master ( 6822a9...ff844e )
by y
01:33
created

Table::count()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Helix\DB;
4
5
use Closure;
6
use Helix\DB;
7
use Helix\DB\SQL\Predicate;
8
9
/**
10
 * Table manipulation using arrays.
11
 *
12
 * Accessing the table as an array produces {@link Column} instances.
13
 *
14
 * @immutable
15
 */
16
class Table extends AbstractTable {
17
18
    /**
19
     * Prepared query cache.
20
     *
21
     * @var Statement[]
22
     */
23
    protected $_cache = [];
24
25
    /**
26
     * `[name => Column]`
27
     *
28
     * @var Column[]
29
     */
30
    protected $columns = [];
31
32
    /**
33
     * @var string
34
     */
35
    protected $name;
36
37
    /**
38
     * @param DB $db
39
     * @param string $name
40
     * @param string[] $columns
41
     */
42
    public function __construct (DB $db, $name, array $columns) {
43
        parent::__construct($db);
44
        $this->name = $name;
45
        foreach ($columns as $column) {
46
            $this->columns[$column] = new Column($db, $column, $this);
47
        }
48
    }
49
50
    /**
51
     * Returns the table name.
52
     *
53
     * @return string
54
     */
55
    final public function __toString () {
56
        return $this->name;
57
    }
58
59
    /**
60
     * `INSERT IGNORE`
61
     *
62
     * @param array $values
63
     * @return int Rows affected.
64
     */
65
    public function apply (array $values): int {
66
        $columns = implode(',', array_keys($values));
67
        $values = implode(', ', $this->db->quoteArray($values));
68
        if ($this->db->getDriver() === 'sqlite') {
69
            return $this->db->exec("INSERT OR IGNORE INTO {$this} ({$columns}) VALUES ({$values})");
70
        }
71
        return $this->db->exec("INSERT IGNORE INTO {$this} ({$columns}) VALUES ({$values})");
72
    }
73
74
    /**
75
     * Caches a prepared query.
76
     *
77
     * @param string $key
78
     * @param Closure $prepare `():Statement`
79
     * @return Statement
80
     */
81
    protected function cache (string $key, Closure $prepare) {
82
        return $this->_cache[$key] ?? $this->_cache[$key] = $prepare->__invoke();
83
    }
84
85
    /**
86
     * @param array $match
87
     * @return int
88
     */
89
    public function count (array $match = []) {
90
        $select = $this->select(['COUNT(*)']);
91
        foreach ($this->db->matchArray($match) as $condition) {
92
            $select->where($condition);
93
        }
94
        return (int)$select->execute()->fetchColumn();
95
    }
96
97
    /**
98
     * Executes a deletion using arbitrary columns.
99
     *
100
     * @see DB::match()
101
     *
102
     * @param array $match
103
     * @return int Rows affected.
104
     */
105
    public function delete (array $match): int {
106
        $match = Predicate::all($this->db->matchArray($match));
107
        return $this->db->exec("DELETE FROM {$this} WHERE {$match}");
108
    }
109
110
    /**
111
     * @return Column[]
112
     */
113
    final public function getColumns (): array {
114
        return $this->columns;
115
    }
116
117
    /**
118
     * @return string
119
     */
120
    final public function getName (): string {
121
        return $this->name;
122
    }
123
124
    /**
125
     * Executes an insertion using arbitrary columns.
126
     *
127
     * @param array $values
128
     * @return Statement
129
     */
130
    public function insert (array $values) {
131
        $columns = implode(',', array_keys($values));
132
        $values = implode(', ', $this->db->quoteArray($values));
133
        return $this->db->query("INSERT INTO {$this} ($columns) VALUES ($values)");
134
    }
135
136
    /**
137
     * @param string $name
138
     * @return bool
139
     */
140
    public function offsetExists ($name): bool {
141
        return isset($this->columns[$name]);
142
    }
143
144
    /**
145
     * @param string $name
146
     * @return Column
147
     */
148
    public function offsetGet ($name) {
149
        return $this->columns[$name];
150
    }
151
152
    /**
153
     * Returns a selection object for columns in the table.
154
     *
155
     * @param string[] $columns Defaults to all columns.
156
     * @return Select
157
     */
158
    public function select (array $columns = []) {
159
        if (!$columns) {
160
            $columns = array_values($this->columns);
161
        }
162
        return new Select($this->db, $this, $columns);
163
    }
164
165
    /**
166
     * Returns a clone with a different name. Columns are also re-qualified.
167
     *
168
     * @param string $name
169
     * @return Table
170
     */
171
    public function setName (string $name) {
172
        $clone = clone $this;
173
        $clone->name = $name;
174
        foreach ($this->columns as $name => $column) {
175
            $clone->columns[$name] = $column->setQualifier($clone);
176
        }
177
        return $clone;
178
    }
179
180
    /**
181
     * Executes an update using arbitrary columns.
182
     *
183
     * @see DB::match()
184
     *
185
     * @param array $values
186
     * @param array $match
187
     * @return int Rows affected.
188
     */
189
    public function update (array $values, array $match): int {
190
        $values = implode(', ', $this->db->matchArray($values));
191
        $match = Predicate::all($this->db->matchArray($match));
192
        return $this->db->exec("UPDATE {$this} SET {$values} WHERE {$match}");
193
    }
194
}