Overview

Namespaces

  • Charcoal
    • Config

Classes

  • Charcoal\Config\AbstractConfig
  • Charcoal\Config\AbstractEntity
  • Charcoal\Config\GenericConfig

Interfaces

  • Charcoal\Config\ConfigInterface
  • Charcoal\Config\ConfigurableInterface
  • Charcoal\Config\DelegatesAwareInterface
  • Charcoal\Config\EntityInterface
  • Charcoal\Config\FileAwareInterface
  • Charcoal\Config\SeparatorAwareInterface

Traits

  • Charcoal\Config\ConfigurableTrait
  • Charcoal\Config\DelegatesAwareTrait
  • Charcoal\Config\FileAwareTrait
  • Charcoal\Config\SeparatorAwareTrait
  • Overview
  • Namespace
  • Class
  1: <?php
  2: 
  3: namespace Charcoal\Config;
  4: 
  5: use ArrayAccess;
  6: use InvalidArgumentException;
  7: 
  8: /**
  9:  * Default data model.
 10:  *
 11:  * ### Notes on {@see \ArrayAccess}:
 12:  *
 13:  * - Keys SHOULD be formatted as "snake_case" (e.g., "first_name") or "camelCase" (e.g., "firstName").
 14:  *   and WILL be converted to the latter {@see PSR-1} to access or assign values.
 15:  * - Values are accessed and assigned via methods and properties which MUST be formatted as "camelCase",
 16:  *   e.g.: `$firstName`, `firstName()`, `setFirstName()`.
 17:  * - A key-value pair is internally passed to a (non-private / non-static) setter method (if present)
 18:  *   or assigned to a (non-private / non-static) property (declared or not) and tracks affected keys.
 19:  */
 20: abstract class AbstractEntity implements EntityInterface
 21: {
 22:     /**
 23:      * Holds a list of all data keys.
 24:      *
 25:      * @var array
 26:      */
 27:     protected $keys = [];
 28: 
 29:     /**
 30:      * Gets the data keys on this entity.
 31:      *
 32:      * @return array
 33:      */
 34:     public function keys()
 35:     {
 36:         return array_keys($this->keys);
 37:     }
 38: 
 39:     /**
 40:      * Gets all data, or a subset, from this entity.
 41:      *
 42:      * @uses   self::offsetExists()
 43:      * @uses   self::offsetGet()
 44:      * @param  string[] $keys Optional. Extracts only the requested data.
 45:      * @return array Key-value array of data, excluding pairs with NULL values.
 46:      */
 47:     public function data(array $keys = null)
 48:     {
 49:         if ($keys === null) {
 50:             $keys = $this->keys();
 51:         }
 52: 
 53:         $data = [];
 54:         foreach ($keys as $key) {
 55:             if (strtolower($key) === 'data') {
 56:                 /** @internal Edge Case: Avoid recursive call */
 57:                 continue;
 58:             }
 59: 
 60:             if (isset($this[$key])) {
 61:                 $data[$key] = $this[$key];
 62:             }
 63:         }
 64:         return $data;
 65:     }
 66: 
 67:     /**
 68:      * Sets data on this entity.
 69:      *
 70:      * @uses   self::offsetSet()
 71:      * @param  array $data Key-value array of data to append.
 72:      * @return self
 73:      */
 74:     public function setData(array $data)
 75:     {
 76:         foreach ($data as $key => $value) {
 77:             if (strtolower($key) === 'data') {
 78:                 /** @internal Edge Case: Avoid recursive call */
 79:                 continue;
 80:             }
 81: 
 82:             $this[$key] = $value;
 83:         }
 84:         return $this;
 85:     }
 86: 
 87:     /**
 88:      * Determines if this entity contains the specified key and if its value is not NULL.
 89:      *
 90:      * @uses   self::offsetExists()
 91:      * @param  string $key The data key to check.
 92:      * @return boolean TRUE if $key exists and has a value other than NULL, FALSE otherwise.
 93:      */
 94:     public function has($key)
 95:     {
 96:         return isset($this[$key]);
 97:     }
 98: 
 99:     /**
100:      * Find an entry of the configuration by its key and retrieve it.
101:      *
102:      * @uses   self::offsetGet()
103:      * @param  string $key The data key to retrieve.
104:      * @return mixed Value of the requested $key on success, NULL if the $key is not set.
105:      */
106:     public function get($key)
107:     {
108:         return $this[$key];
109:     }
110: 
111:     /**
112:      * Assign a value to the specified key on this entity.
113:      *
114:      * @uses   self::offsetSet()
115:      * @param  string $key   The data key to assign $value to.
116:      * @param  mixed  $value The data value to assign to $key.
117:      * @return self Chainable
118:      */
119:     public function set($key, $value)
120:     {
121:         $this[$key] = $value;
122:         return $this;
123:     }
124: 
125:     /**
126:      * Determines if this entity contains the specified key and if its value is not NULL.
127:      *
128:      * Routine:
129:      * - If the entity has a getter method (e.g., "foo_bar" → `fooBar()`),
130:      *   its called and its value is checked;
131:      * - If the entity has a property (e.g., `$fooBar`), its value is checked;
132:      * - If the entity has neither, FALSE is returned.
133:      *
134:      * @see    \ArrayAccess
135:      * @param  string $key The data key to check.
136:      * @throws InvalidArgumentException If the $key is not a string or is a numeric value.
137:      * @return boolean TRUE if $key exists and has a value other than NULL, FALSE otherwise.
138:      */
139:     public function offsetExists($key)
140:     {
141:         if (is_numeric($key)) {
142:             throw new InvalidArgumentException(
143:                 'Entity array access only supports non-numeric keys'
144:             );
145:         }
146: 
147:         $key = $this->camelize($key);
148: 
149:         /** @internal Edge Case: "_" → "" */
150:         if ($key === '') {
151:             return false;
152:         }
153: 
154:         if (is_callable([ $this, $key ])) {
155:             $value = $this->{$key}();
156:         } else {
157:             if (!isset($this->{$key})) {
158:                 return false;
159:             }
160:             $value = $this->{$key};
161:         }
162: 
163:         return ($value !== null);
164:     }
165: 
166:     /**
167:      * Returns the value from the specified key on this entity.
168:      *
169:      * Routine:
170:      * - If the entity has a getter method (e.g., "foo_bar" → `fooBar()`),
171:      *   its called and returns its value;
172:      * - If the entity has a property (e.g., `$fooBar`), its value is returned;
173:      * - If the entity has neither, NULL is returned.
174:      *
175:      * @see    \ArrayAccess
176:      * @param  string $key The data key to retrieve.
177:      * @throws InvalidArgumentException If the $key is not a string or is a numeric value.
178:      * @return mixed Value of the requested $key on success, NULL if the $key is not set.
179:      */
180:     public function offsetGet($key)
181:     {
182:         if (is_numeric($key)) {
183:             throw new InvalidArgumentException(
184:                 'Entity array access only supports non-numeric keys'
185:             );
186:         }
187: 
188:         $key = $this->camelize($key);
189: 
190:         /** @internal Edge Case: "_" → "" */
191:         if ($key === '') {
192:             return null;
193:         }
194: 
195:         if (is_callable([ $this, $key ])) {
196:             return $this->{$key}();
197:         } else {
198:             if (isset($this->{$key})) {
199:                 return $this->{$key};
200:             } else {
201:                 return null;
202:             }
203:         }
204:     }
205: 
206:     /**
207:      * Assigns the value to the specified key on this entity.
208:      *
209:      * Routine:
210:      * - The data key is added to the {@see self::$keys entity's key pool}.
211:      * - If the entity has a setter method (e.g., "foo_bar" → `setFooBar()`),
212:      *   its called and passed the value;
213:      * - If the entity has NO setter method, the value is assigned to a property (e.g., `$fooBar`).
214:      *
215:      * @see    \ArrayAccess
216:      * @param  string $key   The data key to assign $value to.
217:      * @param  mixed  $value The data value to assign to $key.
218:      * @throws InvalidArgumentException If the $key is not a string or is a numeric value.
219:      * @return void
220:      */
221:     public function offsetSet($key, $value)
222:     {
223:         if (is_numeric($key)) {
224:             throw new InvalidArgumentException(
225:                 'Entity array access only supports non-numeric keys'
226:             );
227:         }
228: 
229:         $key = $this->camelize($key);
230: 
231:         /** @internal Edge Case: "_" → "" */
232:         if ($key === '') {
233:             return;
234:         }
235: 
236:         $setter = 'set'.ucfirst($key);
237:         if (is_callable([ $this, $setter ])) {
238:             $this->{$setter}($value);
239:         } else {
240:             $this->{$key} = $value;
241:         }
242: 
243:         $this->keys[$key] = true;
244:     }
245: 
246:     /**
247:      * Removes the value from the specified key on this entity.
248:      *
249:      * Routine:
250:      * - The data key is removed from the {@see self::$keys entity's key pool}.
251:      * - NULL is {@see self::offsetSet() assigned} to the entity.
252:      *
253:      * @see    \ArrayAccess
254:      * @uses   self::offsetSet()
255:      * @param  string $key The data key to remove.
256:      * @throws InvalidArgumentException If the $key is not a string or is a numeric value.
257:      * @return void
258:      */
259:     public function offsetUnset($key)
260:     {
261:         if (is_numeric($key)) {
262:             throw new InvalidArgumentException(
263:                 'Entity array access only supports non-numeric keys'
264:             );
265:         }
266: 
267:         $key = $this->camelize($key);
268: 
269:         /** @internal Edge Case: "_" → "" */
270:         if ($key === '') {
271:             return;
272:         }
273: 
274:         $this[$key] = null;
275:         unset($this->keys[$key]);
276:     }
277: 
278:     /**
279:      * Gets the data that can be serialized with {@see json_encode()}.
280:      *
281:      * @see    \JsonSerializable
282:      * @return array Key-value array of data.
283:      */
284:     public function jsonSerialize()
285:     {
286:         return $this->data();
287:     }
288: 
289:     /**
290:      * Serializes the data on this entity.
291:      *
292:      * @see    \Serializable
293:      * @return string Returns a string containing a byte-stream representation of the object.
294:      */
295:     public function serialize()
296:     {
297:         return serialize($this->data());
298:     }
299: 
300:     /**
301:      * Applies the serialized data to this entity.
302:      *
303:      * @see    \Serializable
304:      * @param  string $data The serialized data to extract.
305:      * @return void
306:      */
307:     public function unserialize($data)
308:     {
309:         $data = unserialize($data);
310:         $this->setData($data);
311:     }
312: 
313:     /**
314:      * Transform a string from "snake_case" to "camelCase".
315:      *
316:      * @param  string $str The string to camelize.
317:      * @return string The camelized string.
318:      */
319:     final protected function camelize($str)
320:     {
321:         if (strstr($str, '_') === false) {
322:             return $str;
323:         }
324:         return lcfirst(implode('', array_map('ucfirst', explode('_', $str))));
325:     }
326: }
327: 
API documentation generated by ApiGen