Completed
Push — master ( 10e333...4c6809 )
by Chris
04:29
created

InMemory::distinct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 11
rs 9.4286
cc 2
eloc 6
nc 2
nop 6
1
<?php
2
namespace Darya\Storage;
3
4
use Darya\Storage\Aggregational;
5
use Darya\Storage\Filterer;
6
use Darya\Storage\Readable;
7
use Darya\Storage\Modifiable;
8
use Darya\Storage\Searchable;
9
use Darya\Storage\Sorter;
10
11
/**
12
 * Darya's in-memory storage interface.
13
 * 
14
 * Useful for unit testing!
15
 * 
16
 * @author Chris Andrew <[email protected]>
17
 */
18
class InMemory implements Readable, Modifiable, Searchable, Aggregational {
19
	
20
	/**
21
	 * The in-memory data.
22
	 * 
23
	 * @var array
24
	 */
25
	protected $data;
26
	
27
	/**
28
	 * Filters results in-memory.
29
	 * 
30
	 * @var Filterer
31
	 */
32
	protected $filterer;
33
	
34
	/**
35
	 * Sorts results in-memory.
36
	 * 
37
	 * @var Sorter
38
	 */
39
	protected $sorter;
40
	
41
	/**
42
	 * Create a new in-memory storage interface with the given data.
43
	 * 
44
	 * @param array $data [optional]
45
	 */
46
	public function __construct(array $data = array()) {
47
		$this->data = $data;
48
		$this->filterer = new Filterer;
49
		$this->sorter = new Sorter;
50
	}
51
	
52
	/**
53
	 * Limit the given data to the given length and offset.
54
	 * 
55
	 * @param array $data
56
	 * @param int   $limit  [optional]
57
	 * @param int   $offset [optional]
58
	 * @return array
59
	 */
60
	protected static function limit(array $data, $limit = 0, $offset = 0) {
61
		return array_slice($data, $offset, $limit ?: null);
62
	}
63
	
64
	/**
65
	 * Retrieve resource data using the given criteria.
66
	 * 
67
	 * Returns an array of associative arrays.
68
	 * 
69
	 * @param string       $resource
70
	 * @param array        $filter   [optional]
71
	 * @param array|string $order    [optional]
72
	 * @param int          $limit    [optional]
73
	 * @param int          $offset   [optional]
74
	 * @return array
75
	 */
76
	public function read($resource, array $filter = array(), $order = array(), $limit = 0, $offset = 0) {
77
		if (empty($this->data[$resource])) {
78
			return array();
79
		}
80
		
81
		$data = $this->filterer->filter($this->data[$resource], $filter);
82
		
83
		$data = $this->sorter->sort($data, $order);
84
		
85
		$data = static::limit($data, $limit, $offset);
86
		
87
		return $data;
88
	}
89
	
90
	/**
91
	 * Retrieve specific fields of a resource.
92
	 * 
93
	 * Returns an array of associative arrays.
94
	 * 
95
	 * @param string       $resource
96
	 * @param array|string $fields
97
	 * @param array        $filter   [optional]
98
	 * @param array|string $order    [optional]
99
	 * @param int          $limit    [optional]
100
	 * @param int          $offset   [optional]
101
	 * @return array
102
	 */
103
	public function listing($resource, $fields, array $filter = array(), $order = array(), $limit = 0, $offset = 0) {
104
		$data = $this->read($resource, $filter, $order, $limit, $offset);
105
		
106
		$fields = (array) $fields;
107
		
108
		$result = array();
109
		
110
		foreach ($data as $row) {
111
			$new = array();
112
			
113
			foreach ($row as $field => $value) {
114
				if (in_array($field, $fields)) {
115
					$new[$field] = $value;
116
				}
117
			}
118
			
119
			if (!empty($new)) {
120
				$result[] = $new;
121
			}
122
		}
123
		
124
		return $result;
125
	}
126
	
127
	/**
128
	 * Count the given resource with an optional filter.
129
	 * 
130
	 * @param string $resource
131
	 * @param array  $filter   [optional]
132
	 * @return int
133
	 */
134 View Code Duplication
	public function count($resource, array $filter = array()) {
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...
135
		if (empty($this->data[$resource])) {
136
			return 0;
137
		}
138
		
139
		return count($this->filterer->filter($this->data[$resource], $filter));
140
	}
141
	
142
	/**
143
	 * Create resource instances in the data store.
144
	 * 
145
	 * @param string $resource
146
	 * @param array  $data
147
	 * @return bool
148
	 */
149
	public function create($resource, $data) {
150
		if (!isset($this->data[$resource])) {
151
			$this->data[$resource] = array();
152
		}
153
		
154
		$this->data[$resource][] = $data;
155
		
156
		return true;
157
	}
158
	
159
	/**
160
	 * Update resource instances in the data store.
161
	 * 
162
	 * @param string $resource
163
	 * @param array  $data
164
	 * @param array  $filter   [optional]
165
	 * @param int    $limit    [optional]
166
	 * @return int|bool
167
	 */
168
	public function update($resource, $data, array $filter = array(), $limit = 0) {
169
		if (empty($this->data[$resource])) {
170
			return;
171
		}
172
		
173
		$affected = 0;
174
		
175
		$this->data[$resource] = $this->filterer->map(
176
			$this->data[$resource],
177
			$filter,
178
			function ($row) use ($data, &$affected) {
179
				foreach ($data as $key => $value) {
180
					$row[$key] = $value;
181
				}
182
				
183
				$affected++;
184
				
185
				return $row;
186
			},
187
			$limit
188
		);
189
		
190
		return $affected;
191
	}
192
	
193
	/**
194
	 * Delete resource instances from the data store.
195
	 * 
196
	 * @param string $resource
197
	 * @param array  $filter   [optional]
198
	 * @param int    $limit    [optional]
199
	 * @return int|bool
200
	 */
201 View Code Duplication
	public function delete($resource, array $filter = array(), $limit = null) {
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...
202
		if (empty($this->data[$resource])) {
203
			return;
204
		}
205
		
206
		$this->data[$resource] = $this->filterer->reject($this->data[$resource], $filter);
207
	}
208
	
209
	/**
210
	 * Search for resource data with fields that match the given query and
211
	 * criteria.
212
	 * 
213
	 * @param string       $resource
214
	 * @param string       $query
215
	 * @param array|string $fields
216
	 * @param array        $filter   [optional]
217
	 * @param array|string $order    [optional]
218
	 * @param int          $limit    [optional]
219
	 * @param int          $offset   [optional]
220
	 * @return array
221
	 */
222
	public function search($resource, $query, $fields, array $filter = array(), $order = array(), $limit = null, $offset = 0) {
223
		if (empty($query) || empty($resource)) {
224
			return $this->read($resource, $filter, $order, $limit, $offset);
225
		}
226
		
227
		$fields = (array) $fields;
228
		$search = array('or' => array());
229
		
230
		foreach ($fields as $field) {
231
			$search['or']["$field like"] = "%$query%";
232
		}
233
		
234
		$filter = array_merge($filter, $search);
235
		
236
		return $this->read($resource, $filter, $order, $limit, $offset);
237
	}
238
	
239
	/**
240
	 * Retrieve the distinct values of the given resource's field.
241
	 * 
242
	 * Returns a flat array of values.
243
	 * 
244
	 * @param string $resource
245
	 * @param string $field
246
	 * @param array  $filter   [optional]
247
	 * @param array  $order    [optional]
248
	 * @param int    $limit    [optional]
249
	 * @param int    $offset   [optional]
250
	 * @return array
251
	 */
252
	public function distinct($resource, $field, array $filter = array(), $order = array(), $limit = 0, $offset = 0) {
253
		$list = array();
254
		
255
		$listing = $this->listing($resource, $field, $filter, $order, $limit, $offset);
256
		
257
		foreach ($listing as $item) {
258
			$list[] = $item[$field];
259
		}
260
		
261
		return array_unique($list);
262
	}
263
	
264
	/**
265
	 * Retrieve the error that occured with the last operation.
266
	 * 
267
	 * Returns false if there was no error.
268
	 * 
269
	 * @return string|bool
270
	 */
271
	public function error() {
272
		return false;
273
	}
274
	
275
}
276