-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Inital commit: ArrayedObject separated from Utilities
- Loading branch information
jimmyoak
committed
Jun 26, 2015
1 parent
12cec04
commit 0fae9d4
Showing
14 changed files
with
749 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.idea | ||
.DS_Store | ||
bin | ||
build | ||
composer.lock | ||
composer.phar | ||
vendor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
language: php | ||
cache: | ||
directories: | ||
- vendor | ||
php: | ||
- 5.6 | ||
- 5.5 | ||
- nightly | ||
|
||
matrix: | ||
fast_finish: true | ||
allow_failures: | ||
- php: nightly | ||
|
||
before_install: | ||
- /home/travis/.phpenv/versions/$(phpenv version-name)/bin/composer self-update | ||
- sh -c "sudo mkdir vendor" | ||
- sh -c "sudo mount -t tmpfs -o size=512M tmpfs vendor" | ||
|
||
before_script: | ||
- alias composer="php -d zend.enable_gc=0 /usr/bin/composer" | ||
- composer install | ||
|
||
script: | ||
- bin/phpunit --coverage-text | ||
|
||
matrix: | ||
allow_failures: | ||
- php: nightly |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# JimmyOak Utilities | ||
|
||
[![Build Status](https://travis-ci.org/jimmyoak/utilities.svg?branch=master)](https://travis-ci.org/jimmyoak/utilities) | ||
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/jimmyoak/utilities/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/jimmyoak/utilities/?branch=master) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "jimmyoak/arrayed-object", | ||
"authors": [ | ||
{ | ||
"name": "Adrián Robles", | ||
"email": "adrian.robles.maiz@gmail.com", | ||
"homepage": "http://github.com/jimmyoak" | ||
} | ||
], | ||
"license": "MIT", | ||
"keywords": ["arrayed", "object", "instantiator", "jimmy", "jimmyoak"], | ||
"require": { | ||
"php": ">=5.5.0", | ||
"jimmyoak/utilities": "2.*" | ||
}, | ||
"require-dev": { | ||
"phpunit/phpunit": ">=3.7.0" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"JimmyOak\\ArrayedObject\\": "src/ArrayedObject/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"JimmyOak\\Test\\ArrayedObject\\": "test/ArrayedObject/" | ||
} | ||
}, | ||
"config": { | ||
"bin-dir": "bin/" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<phpunit | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.6/phpunit.xsd" | ||
cacheTokens="false" | ||
backupGlobals="false" | ||
backupStaticAttributes="false" | ||
colors="true" | ||
convertErrorsToExceptions="true" | ||
convertNoticesToExceptions="true" | ||
convertWarningsToExceptions="true" | ||
stopOnError="true" | ||
stopOnFailure="true" | ||
stopOnIncomplete="false" | ||
stopOnSkipped="false" | ||
syntaxCheck="true" | ||
verbose="true"> | ||
<php> | ||
<ini name="intl.default_locale" value="en_US.UTF-8"/> | ||
<ini name="intl.error_level" value="0"/> | ||
<ini name="memory_limit" value="-1"/> | ||
<ini name="max_execution_time" value="-1"/> | ||
<ini name="date.timezone" value="Europe/Madrid"/> | ||
<ini name="error_reporting" value="E_ALL"/> | ||
</php> | ||
|
||
<testsuites> | ||
<testsuite name="Test Suite"> | ||
<directory>./test</directory> | ||
</testsuite> | ||
</testsuites> | ||
|
||
<filter> | ||
<whitelist> | ||
<directory>./</directory> | ||
<exclude> | ||
<directory>./vendor/</directory> | ||
</exclude> | ||
</whitelist> | ||
</filter> | ||
|
||
<logging> | ||
<log type="junit" target="build/logs/junit.xml"/> | ||
<log type="coverage-clover" target="build/logs/clover.xml"/> | ||
<log type="coverage-html" target="build/coverage"/> | ||
</logging> | ||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
namespace JimmyOak\ArrayedObject; | ||
|
||
use JimmyOak\Collection\Collection; | ||
|
||
class ArrayedObject extends Collection | ||
{ | ||
/** @var string */ | ||
private $class; | ||
|
||
public function __construct($class, $data) | ||
{ | ||
$this->class = $class; | ||
$this->collection = $data; | ||
} | ||
|
||
/** | ||
* @return string | ||
*/ | ||
public function getClass() | ||
{ | ||
return $this->class; | ||
} | ||
|
||
public function getData() | ||
{ | ||
return $this->collection; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
namespace JimmyOak\ArrayedObject; | ||
|
||
class ArrayedObjectFactory | ||
{ | ||
private function __construct() | ||
{ | ||
} | ||
|
||
public static function instance() | ||
{ | ||
static $instance; | ||
|
||
if (null === $instance) { | ||
$instance = new static(); | ||
} | ||
|
||
return $instance; | ||
} | ||
|
||
public function create($object) | ||
{ | ||
return new ArrayedObject(get_class($object), $this->arrayObjectVars($object)); | ||
} | ||
|
||
private function arrayObjectVars($object) | ||
{ | ||
$arrayedObjectFactory = $this; | ||
|
||
$valueProcessor = function ($value) use (&$valueProcessor, $arrayedObjectFactory) { | ||
if (is_object($value)) { | ||
$value = $arrayedObjectFactory->create($value); | ||
} elseif (is_array($value)) { | ||
foreach ($value as &$innerValue) { | ||
$innerValue = $valueProcessor($innerValue); | ||
} | ||
} | ||
|
||
return $value; | ||
}; | ||
|
||
$getObjectVarsClosure = function () use ($valueProcessor) { | ||
return array_map($valueProcessor, get_object_vars($this)); | ||
}; | ||
|
||
$vars = []; | ||
$class = get_class($object); | ||
do { | ||
$bindedGetObjectVarsClosure = \Closure::bind($getObjectVarsClosure, $object, $class); | ||
$vars = array_merge($vars, $bindedGetObjectVarsClosure()); | ||
} while ($class = get_parent_class($class)); | ||
|
||
return $vars; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
<?php | ||
|
||
namespace JimmyOak\ArrayedObject; | ||
|
||
class ArrayedObjectInstantiator | ||
{ | ||
private $specialCasesClasses = [ | ||
\DateTimeInterface::class, | ||
\DateInterval::class, | ||
]; | ||
|
||
private $specialCaseClassFunctionMap = [ | ||
\DateTimeInterface::class => 'createDateTimeInterfaceInstance', | ||
\DateInterval::class => 'createDateIntervalInstance', | ||
]; | ||
|
||
private function __construct() | ||
{ | ||
} | ||
|
||
public static function instance() | ||
{ | ||
static $instance; | ||
|
||
if (null === $instance) { | ||
$instance = new static(); | ||
} | ||
|
||
return $instance; | ||
} | ||
|
||
/** | ||
* @param ArrayedObject $arrayedObject | ||
* | ||
* @return mixed | ||
*/ | ||
public function instantiate(ArrayedObject $arrayedObject) | ||
{ | ||
if ($this->isSpecialCase($arrayedObject)) { | ||
return $this->createSpecialCaseInstance($arrayedObject); | ||
} | ||
|
||
$instance = $this->createClassInstance($arrayedObject); | ||
|
||
$this->fillClassInstance($instance, $arrayedObject->getData()); | ||
|
||
return $instance; | ||
} | ||
|
||
private function createClassInstance(ArrayedObject $arrayedObject) | ||
{ | ||
$instance = (new \ReflectionClass($arrayedObject->getClass()))->newInstanceWithoutConstructor(); | ||
|
||
return $instance; | ||
} | ||
|
||
private function fillClassInstance($instance, $data) | ||
{ | ||
$instantiator = $this; | ||
$valueProcessor = function ($value) use (&$valueProcessor, $instantiator) { | ||
if ($value instanceof ArrayedObject) { | ||
$value = $instantiator->instantiate($value); | ||
} | ||
|
||
if (is_array($value)) { | ||
foreach ($value as &$innerValue) { | ||
$innerValue = $valueProcessor($innerValue); | ||
} | ||
} | ||
|
||
return $value; | ||
}; | ||
|
||
$setObjectVarsClosure = function ($data, $class, &$valueProcessor) { | ||
foreach ($data as $property => $value) { | ||
if (property_exists($class, $property)) { | ||
$value = $valueProcessor($value); | ||
$this->$property = $value; | ||
} | ||
} | ||
}; | ||
|
||
$class = get_class($instance); | ||
do { | ||
$bindedSetObjectVarsClosure = \Closure::bind($setObjectVarsClosure, $instance, $class); | ||
$bindedSetObjectVarsClosure($data, $class, $valueProcessor); | ||
} while ($class = get_parent_class($class)); | ||
} | ||
|
||
private function getSpecialCaseClass(ArrayedObject $arrayedObject) | ||
{ | ||
$class = $arrayedObject->getClass(); | ||
$reflectionClass = new \ReflectionClass($class); | ||
foreach ($this->specialCasesClasses as $specialCaseClass) { | ||
if ($reflectionClass->isSubclassOf($specialCaseClass) || $class === $specialCaseClass) { | ||
return $specialCaseClass; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private function isSpecialCase(ArrayedObject $arrayedObject) | ||
{ | ||
return (bool) $this->getSpecialCaseClass($arrayedObject); | ||
} | ||
|
||
private function createSpecialCaseInstance(ArrayedObject $arrayedObject) | ||
{ | ||
$specialCaseClass = $this->getSpecialCaseClass($arrayedObject); | ||
$functionName = $this->specialCaseClassFunctionMap[$specialCaseClass]; | ||
|
||
return $this->$functionName($arrayedObject); | ||
} | ||
|
||
private function createDateTimeInterfaceInstance(ArrayedObject $arrayedObject) | ||
{ | ||
try { | ||
$instance = (new \ReflectionClass($arrayedObject->getClass()))->newInstanceWithoutConstructor(); | ||
} catch (\ReflectionException $e) { | ||
$instance = (new \ReflectionClass($arrayedObject->getClass()))->newInstance(); | ||
} | ||
|
||
$reflectionClass = new \ReflectionClass(\DateTime::class); | ||
$dateTimeConstructor = $reflectionClass->getConstructor(); | ||
|
||
$data = $arrayedObject->getData(); | ||
$date = isset($data['date']) ? $data['date'] : null; | ||
$dateTimeZone = isset($data['timezone']) ? $data['timezone'] : null; | ||
$dateTimeConstructor->invokeArgs($instance, [$date, new \DateTimeZone($dateTimeZone)]); | ||
|
||
return $instance; | ||
} | ||
|
||
private function createDateIntervalInstance(ArrayedObject $arrayedObject) | ||
{ | ||
$constructionData = ['P0D']; | ||
try { | ||
$instance = (new \ReflectionClass($arrayedObject->getClass()))->newInstanceWithoutConstructor(); | ||
|
||
$reflectionClass = new \ReflectionClass($instance); | ||
|
||
$dateIntervalConstructor = $reflectionClass->getConstructor(); | ||
$dateIntervalConstructor->invokeArgs($instance, $constructionData); | ||
} catch (\ReflectionException $e) { | ||
$instance = (new \ReflectionClass($arrayedObject->getClass()))->newInstanceArgs($constructionData); | ||
} | ||
|
||
$data = $arrayedObject->getData(); | ||
foreach ($data as $property => $value) { | ||
$instance->$property = $value; | ||
} | ||
|
||
return $instance; | ||
} | ||
} |
Oops, something went wrong.