Skip to content

Instantly share code, notes, and snippets.

@bbrothers
Created September 15, 2015 17:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bbrothers/f4b07f349feac36fe7bb to your computer and use it in GitHub Desktop.
Save bbrothers/f4b07f349feac36fe7bb to your computer and use it in GitHub Desktop.
Array/Object Unifier
<?php namespace Acme\Util;
use ArrayAccess;
use Countable;
trait DecoratorTrait
{
/**
* The object or array being decorated
*
* @var object|array
*/
protected $subject;
/**
* {@inheritdoc}
*/
public function toArray()
{
if (is_array($this->subject)) {
return $this->subject;
}
if ($this->subject instanceof ArrayableInterface) {
return $this->subject->toArray();
}
return json_decode(json_encode($this->subject), true);
}
/**
* {@inheritdoc}
*/
public function count()
{
if ($this->subject instanceof Countable) {
return $this->subject->count();
}
return count($this->subject);
}
/**
* Does the property exist on the decorated subject?
*
* @param mixed $offset
*
* @return bool
*/
public function offsetExists($offset)
{
return $this->__isset($offset);
}
/**
* Get the property from the subject
*
* @param mixed $offset
*
* @return mixed
*/
public function offsetGet($offset)
{
return $this->__get($offset);
}
/**
* Set the property on the decorated subject
* This method should be overridden if the subject
* is not an array, has publicly accessible properties
* and does not have a camel cased setter (i.e. foo_property -> setFooProperty)
*
* @param mixed $offset
* @param mixed $value
*
* @return mixed
*/
public function offsetSet($offset, $value)
{
if (is_array($this->subject)) {
return $this->subject[$offset] = $value;
}
$method = 'set' . $this->toCamelCase($offset);
if (method_exists($this->subject, $method)) {
return $this->subject->{$method}($value);
}
return $this->subject->{$offset} = $value;
}
/**
* Unset the property on the decorated subject
*
* @param mixed $offset
*/
public function offsetUnset($offset)
{
$this->__unset($offset);
}
/**
* Get the requested property from the decorated subject
*
* @param mixed $property
*
* @return mixed
*/
public function __get($property)
{
if (is_array($this->subject) or $this->subject instanceof ArrayAccess) {
if ( ! isset($this->subject[$property])) {
throw new \LogicException("The index \"{$property}\" is not set.");
}
return $this->subject[$property];
}
$method = 'get' . $this->toCamelCase($property);
if (method_exists($this->subject, $method)) {
return $this->subject->{$method}();
}
if ( ! property_exists($this->subject, $property)) {
throw new \LogicException(sprintf(
"The property \"%s\" is not set on the class \"%s\".",
$property,
get_class($this->subject)
));
}
return $this->subject->{$property};
}
/**
* Call the requested method on the decorated subject object
*
* @param string $method
* @param array $args
*
* @return mixed
*/
public function __call($method, $args)
{
if (method_exists($this->subject, $method)) {
return call_user_func_array([$this->subject, $method], $args);
}
throw new \BadMethodCallException("The method \"{$method}\" is not defined.");
}
/**
* {@inheritdoc}
*/
public function __isset($parameter)
{
if (is_array($this->subject) or $this->subject instanceof ArrayAccess) {
return isset($this->subject[$parameter]);
}
$methods = [
'get' . $this->toCamelCase($parameter),
'has' . $this->toCamelCase($parameter)
];
foreach ($methods as $method) {
if (method_exists($this->subject, $method)) {
return (bool) $this->subject->{$method}();
}
}
return isset($this->subject->{$parameter});
}
/**
* {@inheritdoc}
*/
public function __unset($parameter)
{
// If its an array or array accessible, just unset it.
if (is_array($this->subject) or $this->subject instanceof ArrayAccess) {
unset($this->subject[$parameter]);
return;
}
// If its an object with a camel cased setter, set it to null
$method = 'set' . $this->toCamelCase($parameter);
if (method_exists($this->subject, $method)) {
$this->subject->{$method}(null);
return;
}
// Assume it's an object and unset the property
unset($this->subject->{$parameter});
}
/**
* {@inheritdoc}
*/
public function jsonSerialize()
{
return $this->toArray();
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return json_encode($this);
}
/**
* Simple helper to change from snake_case to camelCase
*
* @param $str
*
* @return mixed
*/
private function toCamelCase($str)
{
return preg_replace_callback(
'/_([a-z])/',
function ($match) {
return strtoupper($match[1]);
},
$str
);
}
/**
* @return array|object
*/
public function getSubject()
{
return $this->subject;
}
/**
* @param array|object $subject
*
* @return self
*/
public function setSubject($subject)
{
$this->subject = $subject;
return $this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment