1 <?php
2
3 namespace Docolight\Support;
4
5 use ArrayAccess;
6 use CActiveRecord;
7 use JsonSerializable;
8 use Docolight\Http\Contracts\Arrayable;
9
10 /**
11 * This class can wrap your array to an object, make it more safe to access and maintain it's attributes. You can try to fill the attribute with your Model Attributes or a bunch of collection of models.
12 *
13 * Let's take an example:
14 *
15 * ```php
16 * // This is your array:
17 *
18 * $array = array(
19 * 'foo' => 'bar',
20 * 'baz' => 'qux' );
21 *
22 * // Wrap your array with this class:
23 *
24 * $myCoolArray = new \Docolight\Support\Fluent($array);
25 *
26 * // After that you can do something like this:
27 *
28 * echo $myCoolArray->foo; // bar // equals with: echo $myCoolArray['foo'];
29 * echo $myCoolArray->baz; // qux // equals with: echo $myCoolArray['baz'];
30 * echo $myCoolArray->blah; // null // equals with: echo $myCoolArray['blah'];
31 *
32 * $myCoolArray->blah = 'bruh'; // equals with $myCoolArray['blah'] = 'bruh';
33 *
34 * echo $myCoolArray->blah; // bruh
35 * echo $myCoolArray['blah']; // bruh
36 *
37 * // To get single attribute
38 *
39 * $foo = $myCoolArray->get('foo');
40 *
41 *
42 * // To get specific attributes:
43 *
44 * $fooBaz = $myCoolArray->only(array('foo', 'bar'));
45 *
46 *
47 * // To get all atributes except some attributes:
48 *
49 * $fooBlah = $myCoolArray->except(array('baz'));
50 *
51 *
52 * // To get all attributes:
53 *
54 * $attributes = $myCoolArray->get();
55 *
56 *
57 * // To remove single attribute:
58 *
59 * $this->remove('foo');
60 *
61 *
62 * // To remove specific attributes:
63 *
64 * $this->clear(array('foo', 'baz'));
65 *
66 *
67 * // To clear all attributes:
68 *
69 * $myCoolArray->nuke();
70 *
71 *
72 * // To convert all atributes to normal array:
73 *
74 * $myArray = $myCoolArray->toArray();
75 *
76 *
77 * // Oh, once more, you can also echoing the object, and convert them to JSON automagically!
78 *
79 * echo $myCoolArray; // Output is a JSON // or equal with: echo $myCoolArray->toJson();
80 *
81 * // In PHP >= 5.4, you can convert this object to json by:
82 *
83 * $myJSON = json_encode($myCollArray); // Equals with: $myJSON = json_encode($myCoolArray->toArray());
84 * ```
85 * @author Krisan Alfa Timur <krisanalfa@docotel.co.id>
86 */
87 class Fluent implements ArrayAccess, JsonSerializable, Arrayable
88 {
89 /**
90 * Data Attribute in this class.
91 *
92 * @var array
93 */
94 protected $attributes = array();
95
96 /**
97 * Use this to convert attributes to json.
98 *
99 * @var array
100 */
101 protected $jsonAble = null;
102
103 /**
104 * Initialize the class.
105 *
106 * @param array $default Default attribute inside this class
107 */
108 public function __construct(array $default = array())
109 {
110 $this->fill($default);
111 }
112
113 /**
114 * Initialize the class statically.
115 *
116 * @param array $default Default attribute inside this class
117 */
118 public static function make(array $default = array())
119 {
120 return new static($default);
121 }
122
123 /**
124 * Determine if index is exist in attributes.
125 *
126 * @param string $index
127 *
128 * @return bool
129 */
130 public function has($index)
131 {
132 return isset($this->attributes[$index]);
133 }
134
135 /**
136 * Remove an attributes.
137 *
138 * @param string $index
139 */
140 public function remove($index)
141 {
142 if ($this->has($index)) {
143 unset($this->attributes[$index]);
144 }
145 }
146
147 /**
148 * Set an attribute value.
149 *
150 * @param string $index
151 * @param mixed $value
152 */
153 public function set($index, $value)
154 {
155 $this->attributes[$index] = $value;
156 }
157
158 /**
159 * {@inheritdoc}
160 */
161 public function fill($attributes)
162 {
163 $this->attributes = $attributes;
164 }
165
166 /**
167 * Bulk remove attributes by an array contains indexes name you want to remove.
168 *
169 * @param array $attributes
170 *
171 * @return
172 */
173 public function clear(array $attributes)
174 {
175 foreach ($attributes as $index) {
176 $this->remove($index);
177 }
178 }
179
180 /**
181 * Get a list of array which only if the key is exists on the given argument.
182 *
183 * @param array $attributes List of array key you want to get from your attributes.
184 *
185 * @see Arr::only()
186 *
187 * @return array
188 */
189 public function only(array $attributes)
190 {
191 return Arr::only($this->attributes, $attributes);
192 }
193
194 /**
195 * Get a list of array except the given array of index.
196 *
197 * @param array $attributes List of array keys you want to exclude from your array.
198 *
199 * @see Arr::except()
200 *
201 * @return array
202 */
203 public function except(array $attributes)
204 {
205 return Arr::except($this->attributes, $attributes);
206 }
207
208 /**
209 * Reset the attributes.
210 *
211 * @param array $default Default attributes after nuking current attributes.
212 */
213 public function nuke(array $default = array())
214 {
215 $this->attributes = $default;
216 }
217
218 /**
219 * Get an attribute value.
220 *
221 * @param string $index
222 * @param mixed $default Default value if index doesn't exist
223 *
224 * @return mixed
225 */
226 public function get($index, $default = null)
227 {
228 return $this->has($index) ? $this->attributes[$index] : value($default);
229 }
230
231 /**
232 * Get attributes value.
233 *
234 * @param mixed $attributes If it's null, it will return the whole attributes, if it's array, it will fetch only the given array value
235 * @param mixed $default Default value if attributes don't exist
236 *
237 * @return mixed
238 */
239 public function attributes($attributes = null, $default = null)
240 {
241 if (is_null($attributes)) {
242 return $this->attributes;
243 }
244
245 if (is_array($attributes)) {
246 $return = $this->only($attributes);
247
248 return empty($return) ? value($default) : $return;
249 }
250
251 return value($default);
252 }
253
254 /**
255 * Convert this implementation object to array.
256 *
257 * @param mixed $attributes Something you want to convert to array.
258 *
259 * @return array
260 *
261 * @see Arr::arToArray()
262 */
263 public function toArray($attributes = null)
264 {
265 if ($this->jsonAble === null) {
266 $jsonAble = array();
267
268 if ($attributes === null) {
269 $attributes = $this->attributes;
270 }
271
272 foreach ($attributes as $key => $value) {
273 if ($value instanceof CActiveRecord) {
274 $jsonAble[$key] = Arr::arToArray($value);
275 } elseif ($value instanceof Arrayable) {
276 $jsonAble[$key] = $value->castToArray();
277 } elseif (is_object($value)) {
278 $jsonAble[$key] = (array) $value;
279 } elseif (is_array($value)) {
280 $jsonAble[$key] = $this->toArray($value);
281 } else {
282 $jsonAble[$key] = $value;
283 }
284 }
285
286 $this->jsonAble = $jsonAble;
287 }
288
289 return $this->jsonAble;
290 }
291
292 /**
293 * {@inheritdoc}
294 */
295 public function castToArray()
296 {
297 return $this->toArray();
298 }
299
300 /**
301 * Convert attributes to readable JSON.
302 *
303 * @param const $options JSON Decoding options.
304 *
305 * @return string
306 */
307 public function toJson($options = null)
308 {
309 return json_encode($this->toArray(), $options);
310 }
311
312 /**
313 * Set an attribute value.
314 *
315 * @param string $index
316 * @param mized $value
317 */
318 public function offsetSet($index, $value)
319 {
320 $this->set($index, $value);
321 }
322
323 /**
324 * Determine if index is exist in attributes.
325 *
326 * @param string $index
327 *
328 * @return bool
329 */
330 public function offsetExists($index)
331 {
332 return $this->has($index);
333 }
334
335 /**
336 * Remove an attributes.
337 *
338 * @param string $index
339 */
340 public function offsetUnset($index)
341 {
342 $this->remove($index);
343 }
344
345 /**
346 * Get an attribute value.
347 *
348 * @param string $index
349 * @param mixed $default Default value if index doesn't exist
350 *
351 * @return mixed
352 */
353 public function offsetGet($index)
354 {
355 return $this->get($index);
356 }
357
358 /**
359 * JsonSerializable implementation.
360 *
361 * @return array
362 */
363 public function jsonSerialize()
364 {
365 return $this->toArray();
366 }
367
368 /**
369 * Set an attribute value.
370 *
371 * @param string $index
372 * @param mized $value
373 */
374 public function __set($index, $value)
375 {
376 $this->set($index, $value);
377 }
378
379 /**
380 * Get an attribute value.
381 *
382 * @param string $index
383 * @param mixed $default Default value if index doesn't exist
384 *
385 * @return mixed
386 */
387 public function __get($index)
388 {
389 return $this->get($index);
390 }
391
392 /**
393 * Determine if index exists in attributes.
394 *
395 * @param string $index
396 *
397 * @return bool
398 */
399 public function __isset($index)
400 {
401 return $this->has($index);
402 }
403
404 /**
405 * Remove an attributes.
406 *
407 * @param string $index
408 */
409 public function __unset($index)
410 {
411 $this->remove($index);
412 }
413
414 /**
415 * Convert your collection to JSON.
416 *
417 * @return string
418 */
419 public function __toString()
420 {
421 return $this->toJson();
422 }
423 }
424