/** * Initializes the repository instance. * * Initializes the repository instance based on a classes meta information. * * @param Arachnid $entityManager The entity manager. * @param Meta\GraphElement $meta The classes meta information. */ public function __construct(Arachnid $entityManager, Meta\GraphElement $meta) { $this->entityManager = $entityManager; $this->class = $meta->getName(); $this->meta = $meta; }
/** * Find properties based on a method name. * * This overrides graph elements findProperty, in order to allow for finding the start/end properties. * * @param string $name Method name. * @return Property|null Property if found, otherwise null. */ function findProperty($name) { //Get the property from the method name $property = Reflection::getProperty($name); if ($this->start->matches($property)) { return $this->start; } if ($this->end->matches($property)) { return $this->end; } return parent::findProperty($name); }
/** * Creates a proxy class for a graph element. * * This method will create a proxy class for an entity that extends the required class and implements * LRezek\Arachnid\Proxy\Entity. This class will be generated and stored in the directory specified by the $proxyDir * property of this class. This is done so that the object returned by a query seemingly matches the object type * being queried for, while retaining its ID and other required information. * * @param GraphElement $meta The meta for the entity object being proxied. * @return mixed An instance of the proxy class. * @throws \LRezek\Arachnid\Exception If something goes wrong in file writing. */ private function createProxy(GraphElement $meta) { //Get the proxy class name, as well as the regular class name $proxyClass = $meta->getProxyClass(); $className = $meta->getName(); //If the class already exists, just make an instance of it with the correct properties and return it. if (class_exists($proxyClass, false)) { return $this->newInstance($proxyClass); } //Create a target file for the class $targetFile = "{$this->proxyDir}/{$proxyClass}.php"; //If the file doesn't exist if ($this->debug || !file_exists($targetFile)) { //Initialize functions $functions = ''; $reflectionClass = new \ReflectionClass($className); //Loop through entities public methods foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { //If the method isn't a constructor, destructor, or final, add it to the methods via method proxy. if (!$method->isConstructor() && !$method->isDestructor() && !$method->isFinal()) { $functions .= $this->methodProxy($method, $meta); } } //Get the properties and primary key. $properties = $meta->getProperties(); $properties[] = $meta->getPrimaryKey(); //Filter out private properties $properties = array_filter($properties, function ($property) { return !$property->isPrivate(); }); //Create an array map by property name $properties = array_map(function ($property) { return $property->getName(); }, $properties); //Create php code for properties. $properties = var_export($properties, true); //Create the actual class. $content = <<<CONTENT <?php class {$proxyClass} extends {$className} implements LRezek\\Arachnid\\Proxy\\Entity { private \$neo4j_hydrated = array(); private \$neo4j_meta; private \$neo4j_entity; private \$neo4j_loadCallback; function getEntity() { \$entity = new {$className}; foreach (\$this->neo4j_meta->getProperties() as \$prop) { \$prop->setValue(\$entity, \$prop->getValue(\$this)); } \$prop = \$this->neo4j_meta->getPrimaryKey(); \$prop->setValue(\$entity, \$prop->getValue(\$this)); return \$entity; } {$functions} function __addHydrated(\$name) { \$this->neo4j_hydrated[] = \$name; } function __setMeta(\$meta) { \$this->neo4j_meta = \$meta; } function __setEntity(\$entity) { \$this->neo4j_entity = \$entity; } function __getEntity() { return \$this->neo4j_entity; } function __setLoadCallback(\$loadCallback) { \$this->neo4j_loadCallback = \$loadCallback; } private function __load(\$name, \$propertyName) { //Already hydrated if(in_array(\$propertyName, \$this->neo4j_hydrated)) { return; } if(! \$this->neo4j_meta) { throw new \\LRezek\\Arachnid\\Exception('Proxy not fully initialized.'); } \$property = \$this->neo4j_meta->findProperty(\$name); if(strpos(\$name, 'set') === 0) { \$this->__addHydrated(\$propertyName); return; } //Make property node if(\$property->isStart() || \$property->isEnd()) { \$loader = \$this->neo4j_loadCallback; //Get the node if(\$property->isStart()) { \$node = \$this->neo4j_entity->getStartNode(); } else { \$node = \$this->neo4j_entity->getEndNode(); } \$node = \$loader(\$node); //Set the property \$property->setValue(\$this, \$node); } //Hydrate the property \$this->__addHydrated(\$propertyName); } function __sleep() { return {$properties}; } } CONTENT; //Make sure the proxy directory is an actual directory if (!is_dir($this->proxyDir)) { if (false === @mkdir($this->proxyDir, 0775, true)) { throw new Exception('Proxy Dir is not writable.'); } } else { if (!is_writable($this->proxyDir)) { throw new Exception('Proxy Dir is not writable.'); } } //Write the file file_put_contents($targetFile, $content); } //Add file to class loader require $targetFile; //Return an instance of the proxy class return $this->newInstance($proxyClass); }