Completed
Push — master ( 2d3c47...157dd8 )
by Chris
03:55
created

Storage::run()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace Darya\Database;
3
4
use Darya\Database\Storage\Query as DatabaseStorageQuery;
5
use Darya\Database\Storage\Result as DatabaseStorageResult;
6
use Darya\Storage\Aggregational;
7
use Darya\Storage\Readable;
8
use Darya\Storage\Modifiable;
9
use Darya\Storage\Queryable;
10
use Darya\Storage\Searchable;
11
use Darya\Storage\Query as StorageQuery;
12
use Darya\Storage\Query\Builder as QueryBuilder;
13
14
/**
15
 * Darya's database storage implementation.
16
 * 
17
 * TODO: Remove listing and add $columns parameter to read().
18
 * 
19
 * @author Chris Andrew <[email protected]>
20
 */
21
class Storage implements Aggregational, Readable, Modifiable, Queryable, Searchable
22
{
23
	/**
24
	 * @var Connection
25
	 */
26
	protected $connection;
27
	
28
	/**
29
	 * Instantiate a database-driven data store.
30
	 * 
31
	 * @param Connection $connection
32
	 */
33
	public function __construct(Connection $connection)
34
	{
35
		$this->connection = $connection;
36
	}
37
	
38
	/**
39
	 * Flatten the given data to the values of the given key.
40
	 * 
41
	 * @param array  $data
42
	 * @param string $key
43
	 * @return array
44
	 */
45
	protected static function flatten(array $data, $key)
46
	{
47
		$flat = array();
48
		
49
		foreach ($data as $row) {
50
			if (isset($row[$key])) {
51
				$flat[] = $row[$key];
52
			}
53
		}
54
		
55
		return $flat;
56
	}
57
	
58
	/**
59
	 * Prepare the given order value as an array.
60
	 * 
61
	 * @param array|string $order
62
	 * @return array
63
	 */
64
	protected static function prepareOrder($order)
65
	{
66
		if (is_array($order)) {
67
			return $order;
68
		}
69
		
70
		if (!is_string($order)) {
71
			return array();
72
		}
73
		
74
		return array($order => 'asc');
75
	}
76
	
77
	/**
78
	 * Retrieve the distinct values of the given database column.
79
	 * 
80
	 * Returns a flat array of values.
81
	 * 
82
	 * @param string $table
83
	 * @param string $column
84
	 * @param array  $filter [optional]
85
	 * @param array  $order  [optional]
86
	 * @param int    $limit  [optional]
87
	 * @param int    $offset [optional]
88
	 * @return array
89
	 */
90
	public function distinct($table, $column, array $filter = array(), $order = array(), $limit = 0, $offset = 0)
91
	{
92
		$query = new StorageQuery($table, array($column), $filter, static::prepareOrder($order), $limit, $offset);
93
		$query->distinct();
94
		
95
		return static::flatten($this->run($query)->data, $column);
96
	}
97
	
98
	/**
99
	 * Retrieve all values of the given database columns.
100
	 * 
101
	 * Returns an array of associative arrays.
102
	 * 
103
	 * @param string       $table
104
	 * @param array|string $columns
105
	 * @param array        $filter [optional]
106
	 * @param array|string $order  [optional]
107
	 * @param int          $limit  [optional]
108
	 * @param int          $offset [optional]
109
	 * @return array
110
	 */
111
	public function listing($table, $columns, array $filter = array(), $order = array(), $limit = null, $offset = 0)
112
	{
113
		$query = new StorageQuery($table, (array) $columns, $filter, static::prepareOrder($order), $limit, $offset);
114
		
115
		return $this->run($query)->data;
116
	}
117
	
118
	/**
119
	 * Retrieve database rows that match the given criteria.
120
	 * 
121
	 * Returns an array of associative arrays.
122
	 * 
123
	 * @param string       $table
124
	 * @param array        $filter [optional]
125
	 * @param array|string $order  [optional]
126
	 * @param int          $limit  [optional]
127
	 * @param int          $offset [optional]
128
	 * @return array
129
	 */
130
	public function read($table, array $filter = array(), $order = array(), $limit = null, $offset = 0)
131
	{
132
		$query = new StorageQuery($table, array(), $filter, static::prepareOrder($order), $limit, $offset);
133
		
134
		return $this->run($query)->data;
135
	}
136
	
137
	/**
138
	 * Count the rows that match the given criteria.
139
	 * 
140
	 * @param string $table
141
	 * @param array  $filter [optional]
142
	 * @return int
143
	 */
144
	public function count($table, array $filter = array())
145
	{
146
		$query = new StorageQuery($table, array(1), $filter);
147
		
148
		return $this->run($query)->count;
149
	}
150
	
151
	/**
152
	 * Insert a record with the given data into the given table.
153
	 * 
154
	 * Returns the ID of the new row or false if an error occurred.
155
	 * 
156
	 * @param string $table
157
	 * @param array  $data
158
	 * @return int
159
	 */
160
	public function create($table, $data)
161
	{
162
		$query = new StorageQuery($table);
163
		$query->create($data);
164
		
165
		return $this->run($query)->insertId;
166
	}
167
	
168
	/**
169
	 * Update rows that match the given criteria using the given data.
170
	 * 
171
	 * Returns the number of rows affected by the update operation. If no rows
172
	 * are affected, returns true if there were no errors, false otherwise.
173
	 * 
174
	 * Refuses to perform the query if the given filter evaluates to an
175
	 * empty where clause.
176
	 * 
177
	 * @param string $table
178
	 * @param array  $data
179
	 * @param array  $filter [optional]
180
	 * @param int    $limit  [optional]
181
	 * @return int|bool
182
	 */
183
	public function update($table, $data, array $filter = array(), $limit = null)
184
	{
185
		if (!$data) {
186
			return true;
187
		}
188
		
189
		$query = new StorageQuery($table, array(), $filter, array(), $limit);
190
		$query->update($data);
191
		
192
		$result = $this->run($query);
193
		
194
		return $result->affected ?: !$this->error();
195
	}
196
	
197
	/**
198
	 * Delete rows from the given table using the given filter and limit.
199
	 * 
200
	 * Returns the number of rows affected by the delete operation.
201
	 * 
202
	 * Refuses to perform the operation if the table is a wildcard ('*'), empty,
203
	 * or if the given filter evaluates to an empty where clause.
204
	 * 
205
	 * @param string $table
206
	 * @param array  $filter [optional]
207
	 * @param int    $limit  [optional]
208
	 * @return int|bool
209
	 */
210
	public function delete($table, array $filter = array(), $limit = null)
211
	{
212
		if ($table == '*' || empty($table) || empty($filter)) {
213
			return null;
214
		}
215
		
216
		$query = new StorageQuery($table, array(), $filter, array(), $limit);
217
		$query->delete();
218
		
219
		$result = $this->run($query);
220
		
221
		return $result->affected ?: !$this->error();
222
	}
223
	
224
	/**
225
	 * Execute the given storage query.
226
	 * 
227
	 * @param StorageQuery $storageQuery
228
	 * @return DatabaseStorageResult
229
	 */
230
	public function run(StorageQuery $storageQuery)
231
	{
232
		$query = $this->connection->translate($storageQuery);
233
		
234
		$databaseResult = $this->connection->query($query->string, $query->parameters);
235
		
236
		return DatabaseStorageResult::createWithDatabaseResult($storageQuery, $databaseResult);
237
	}
238
	
239
	/**
240
	 * Open a query on the given resource.
241
	 * 
242
	 * Optionally accepts the column(s) to retrieve in the case of a read query.
243
	 * 
244
	 * @param string       $resource
245
	 * @param array|string $columns  [optional]
246
	 * @return QueryBuilder
247
	 */
248
	public function query($resource, $columns = array())
249
	{
250
		$query = new DatabaseStorageQuery($resource, (array) $columns);
251
		
252
		return new QueryBuilder($query, $this);
253
	}
254
	
255
	/**
256
	 * Search for rows in the given table with fields that match the given query
257
	 * and criteria.
258
	 * 
259
	 * @param string       $table
260
	 * @param string       $query
261
	 * @param array|string $columns [optional]
262
	 * @param array        $filter  [optional]
263
	 * @param array|string $order   [optional]
264
	 * @param int          $limit   [optional]
265
	 * @param int          $offset  [optional]
266
	 * @return array
267
	 */
268
	public function search($table, $query, $columns = array(), array $filter = array(), $order = array(), $limit = null, $offset = 0)
269
	{
270
		$order = static::prepareOrder($order);
271
		
272
		if (!is_string($query) || empty($columns)) {
273
			return $this->read($table, $filter, $order, $limit, $offset);
274
		}
275
		
276
		$columns = (array) $columns;
277
		$search = array('or' => array());
278
		
279
		foreach ($columns as $column) {
280
			$search['or']["$column like"] = "%$query%";
281
		}
282
		
283
		$filter = array_merge($filter, $search);
284
		
285
		$query = new StorageQuery($table, array(), $filter, $order, $limit, $offset);
286
		
287
		return $this->run($query)->data;
288
	}
289
	
290
	/**
291
	 * Retrieve the error that occurred with the last operation.
292
	 * 
293
	 * Returns false if there was no error.
294
	 * 
295
	 * @return string|bool
296
	 */
297
	public function error()
298
	{
299
		if ($error = $this->connection->error()) {
300
			return $error->message;
301
		}
302
		
303
		return false;
304
	}
305
}
306