Skip to content

Instantly share code, notes, and snippets.

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 Ocramius/0f60374f35993ea8110c to your computer and use it in GitHub Desktop.
Save Ocramius/0f60374f35993ea8110c to your computer and use it in GitHub Desktop.
<?php
namespace EntityMapperFramework {
class EntityMapper {
public function __construct() {
stream_wrapper_register('dynamicproxygenerator', __NAMESPACE__ . '\DynamicProxyGeneratorStream');
}
public function createProxy($entity) {
$class = get_class($entity);
$proxyClass = $class . 'Proxy';
include_once "dynamicproxygenerator://$class?strategy=ProxyProtectedPropertyMapperStrategy";
return (new $proxyClass)->setEntity($entity);
}
}
class DynamicProxyGeneratorStream {
protected $position;
protected $currentCode;
public function stream_open($path, $mode, $options, &$opened_path) {
$parsed = parse_url($path);
$fqClassName = $parsed['host'];
parse_str($parsed['query'], $queryParts);
$strategy = $queryParts['strategy']; // strategy could be picked at runtime, or by configuration
$ref = new \ReflectionClass($fqClassName);
$namespace = $ref->getNamespaceName();
$className = $ref->getShortName();
$this->currentCode = "<?php namespace {$namespace} { "
. "class {$className}Proxy extends \\{$fqClassName} {"
. "use \EntityMapperFramework\ProxyEntityTrait;"
. "use \EntityMapperFramework\\{$strategy}Trait; } }";
$this->position = 0;
return true;
}
public function stream_read($count) {
$ret = substr($this->currentCode, $this->position, $count);
$this->position += strlen($ret);
return $ret;
}
public function stream_eof() {
return $this->position >= strlen($this->currentCode);
}
public function stream_stat() {
$t = time();
return array(0, 0, 0, 0, 0, 0, 0, strlen($this->currentCode), $t, $t, $t, -1, -1);
}
}
trait ProxyEntityTrait {
protected $entity;
public function setEntity($entity) {
$this->entity = $entity;
return $this;
}
}
trait ProxyProtectedPropertyMapperStrategyTrait {
public function map($mapping, $data) {
foreach ($data as $n => $v) {
$this->entity->{$mapping[$n]} = $v;
}
return $this;
}
}
}
// Represents the model part of the application
namespace MyApplication\Model {
class FooEntity /* a POPO Entity, should have no knowledge of persistence layer */ {
protected $aNumber;
protected $bString;
public function getANumber() { return $this->aNumber; }
public function getBString() { return $this->bString; }
}
class MySimpleOrmFooRepository /* implements FooRepository */ {
protected $fooMap = ['a_number' => 'aNumber', 'b_string' => 'bString'];
protected $proxies = [];
public function __construct() {
$this->entityMapper = new \EntityMapperFramework\EntityMapper; // should be injected service
}
public function getFoo() {
$foo = new FooEntity;
$proxy = $this->entityMapper->createProxy($foo);
$this->proxies[spl_object_hash($proxy)] = $proxy; // for future use, like calling Repo::save()
$proxy->map($this->fooMap, ['a_number' => 15, 'b_string' => 'The B Team']);
return $foo;
}
}
}
// Represents the code that calls into the model, like a controller or other service
namespace {
$repo = new MyApplication\Model\MySimpleOrmFooRepository;
$foo = $repo->getFoo();
assert($foo->getANumber() == 15);
assert($foo->getBString() == 'The B Team');
echo "Assertions passed\n"; var_dump($foo);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment