diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index 5068f740e..cb915f1e9 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -1134,7 +1134,9 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count } if ($deep) { foreach ($this->_references as $key => $relation) { - $a[$key] = $relation->toArray($deep, $prefixKey); + if (!$relation instanceof Doctrine_Null) { + $a[$key] = $relation->toArray($deep, $prefixKey); + } } } return array_merge($a, $this->_values); diff --git a/lib/Doctrine/Resource/Access.php b/lib/Doctrine/Resource/Access.php index 6e965f8b3..27c23666e 100644 --- a/lib/Doctrine/Resource/Access.php +++ b/lib/Doctrine/Resource/Access.php @@ -31,110 +31,5 @@ * @link www.phpdoctrine.com * @since 1.0 */ -class Doctrine_Resource_Access implements ArrayAccess -{ - /** - * setArray - * - * @param array $array an array of key => value pairs - * @since 1.0 - * @return Doctrine_Access - */ - public function setArray(array $array) - { - foreach ($array as $k=>$v) { - $this->set($k,$v); - } - - return $this; - } - /** - * __set an alias of set() - * - * @see set, offsetSet - * @param $name - * @param $value - * @since 1.0 - * @return void - */ - public function __set($name,$value) - { - $this->set($name,$value); - } - /** - * __get -- an alias of get() - * - * @see get, offsetGet - * @param mixed $name - * @since 1.0 - * @return mixed - */ - public function __get($name) - { - return $this->get($name); - } - /** - * __isset() - * - * @param string $name - * @since 1.0 - * @return boolean whether or not this object contains $name - */ - public function __isset($name) - { - return $this->contains($name); - } - /** - * __unset() - * - * @param string $name - * @since 1.0 - * @return void - */ - public function __unset($name) - { - return $this->remove($name); - } - /** - * @param mixed $offset - * @return boolean whether or not this object contains $offset - */ - public function offsetExists($offset) - { - return $this->contains($offset); - } - /** - * offsetGet an alias of get() - * @see get, __get - * @param mixed $offset - * @return mixed - */ - public function offsetGet($offset) - { - return $this->get($offset); - } - /** - * sets $offset to $value - * @see set, __set - * @param mixed $offset - * @param mixed $value - * @return void - */ - public function offsetSet($offset, $value) - { - if ( ! isset($offset)) { - $this->add($value); - } else { - $this->set($offset, $value); - } - } - /** - * unset a given offset - * @see set, offsetSet, __set - * @param mixed $offset - */ - public function offsetUnset($offset) - { - return $this->remove($offset); - } -} \ No newline at end of file +class Doctrine_Resource_Access extends Doctrine_Access +{ } \ No newline at end of file diff --git a/lib/Doctrine/Resource/Client.php b/lib/Doctrine/Resource/Client.php index 2592dacaf..c2ce7de16 100644 --- a/lib/Doctrine/Resource/Client.php +++ b/lib/Doctrine/Resource/Client.php @@ -64,7 +64,7 @@ class Doctrine_Resource_Client extends Doctrine_Resource $path = '/tmp/' . md5(serialize($this->getConfig())); $classesPath = $path.'.classes.php'; - if (!file_exists($path)) { + if (file_exists($path)) { $schema = file_get_contents($path); } else { $request = new Doctrine_Resource_Request(); @@ -74,7 +74,7 @@ class Doctrine_Resource_Client extends Doctrine_Resource $schema = $request->execute(); if ($schema) { - file_put_contents($path, $schema); + file_put_contents($path, Doctrine_Parser::dump($schema, $this->getConfig()->get('format'))); } } @@ -86,6 +86,8 @@ class Doctrine_Resource_Client extends Doctrine_Resource $build = " $details) { $build .= "class " . $className . " extends Doctrine_Resource_Record { protected \$_model = '".$className."'; public function __construct(\$loadRelations = true) { parent::__construct(\$this->_model, \$loadRelations); } }\n"; + + $schema['schema'][$className]['relations'] = isset($schema['relations'][$className]) ? $schema['relations'][$className]:array(); } file_put_contents($classesPath, $build); @@ -99,6 +101,64 @@ class Doctrine_Resource_Client extends Doctrine_Resource public function getTable($table) { - return new Doctrine_Resource_Table($table); + static $instance; + + if(!isset($instance[$table])) { + $instance[$table] = new Doctrine_Resource_Table($table); + } + + return $instance[$table]; + } + + public function printSchema() + { + $schema = $this->getConfig('schema'); + + echo '

Schema

'; + + echo ''; + + exit; } } \ No newline at end of file diff --git a/lib/Doctrine/Resource/Collection.php b/lib/Doctrine/Resource/Collection.php index 6d84c8cf8..78aa47044 100644 --- a/lib/Doctrine/Resource/Collection.php +++ b/lib/Doctrine/Resource/Collection.php @@ -36,12 +36,18 @@ class Doctrine_Resource_Collection extends Doctrine_Resource_Access implements C protected $_data = array(); protected $_config = array(); protected $_model = null; + protected $_parent = null; public function __construct($model) { $this->_model = $model; } + public function setParent($parent) + { + $this->_parent = $parent; + } + public function getConfig($key = null) { return Doctrine_Resource_Client::getInstance()->getConfig($key); @@ -52,16 +58,24 @@ class Doctrine_Resource_Collection extends Doctrine_Resource_Access implements C return count($this->_data); } - public function get($get) + public function get($key) { - if (isset($this->_data[$get])) { - return $this->_data[$get]; + if (!$key || !isset($this->_data[$key])) { + return $this->add(); + } else { + return $this->_data[$key]; } } - public function set($set, $value) + public function set($key, $value) { - $this->_data[$set] = $value; + if (!$key || !isset($this->_data[$key])) { + $this->_data[$key] = $value; + } else { + $val = $this->add(); + + $val->_data[$key] = $value; + } } public function add($value = null) @@ -69,7 +83,19 @@ class Doctrine_Resource_Collection extends Doctrine_Resource_Access implements C if (!$value) { $model = $this->_model; - $value = new $model(); + $value = new $model(false); + $table = $value->getTable(); + $relation = $table->getRelationByClassName(get_class($this->_parent)); + $alias = $relation['alias']; + + if ($relation['type'] === Doctrine_Relation::ONE) { + $value->set($alias, $this->_parent); + } else { + $collection = new Doctrine_Resource_Collection($relation['class']); + $collection[] = $this->_parent; + + $value->set($alias, $collection); + } } $this->_data[] = $value; @@ -87,13 +113,13 @@ class Doctrine_Resource_Collection extends Doctrine_Resource_Access implements C return isset($this->_data[0]) ? $this->_data[0]:null; } - public function toArray() + public function toArray($deep = false) { $array = array(); foreach ($this->_data as $key => $record) { if ($record->exists() || $record->hasChanges()) { - $array[$this->_model . '_' .$key] = $record->toArray(); + $array[$this->_model . '_' .$key] = $record->toArray($deep); } } diff --git a/lib/Doctrine/Resource/Query.php b/lib/Doctrine/Resource/Query.php index 1a199fd77..6a172c037 100644 --- a/lib/Doctrine/Resource/Query.php +++ b/lib/Doctrine/Resource/Query.php @@ -57,17 +57,22 @@ class Doctrine_Resource_Query $request->set('params', $params); $request->set('format', $this->getConfig()->get('format')); $request->set('type', 'query'); + $request->set('model', $this->getModel()); $response = $request->execute(); // If we have a response then lets parse it and hydrate it - if ($response) { - $array = Doctrine_Parser::load($response, $this->getConfig()->get('format')); - - return $request->hydrate($array, $this->getModel()); + if (!empty($response)) { + return $request->hydrate($response, $this->getModel()); // Otherwise lets return an empty collection for the queried for model } else { - return new Doctrine_Resource_Collection($this->getModel()); + $model = $this->getModel(); + + $collection = new Doctrine_Resource_Collection($this->getModel()); + + $collection[] = new $model(false); + + return $collection; } } diff --git a/lib/Doctrine/Resource/Record.php b/lib/Doctrine/Resource/Record.php index 940b7dae2..cd7f5a59b 100644 --- a/lib/Doctrine/Resource/Record.php +++ b/lib/Doctrine/Resource/Record.php @@ -35,13 +35,11 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count { protected $_data = array(); protected $_model = null; - protected $_table = null; protected $_changes = array(); public function __construct($model, $loadRelations = true) { $this->_model = $model; - $this->_table = Doctrine_Resource_Client::getInstance()->getTable($model); $this->initialize($loadRelations); } @@ -74,6 +72,7 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count $this->_data[$relation['alias']] = new $relation['class'](false); } else { $this->_data[$relation['alias']] = new Doctrine_Resource_Collection($relation['class']); + $this->_data[$relation['alias']]->setParent($this); } } } @@ -86,18 +85,65 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count public function get($key) { + if (!$key) { + return; + } + + if (!isset($this->_data[$key]) && $this->getTable()->hasRelation($key)) { + $this->_data[$key] = $this->createRelation($key); + } + + if (!array_key_exists($key, $this->_data)) { + throw new Doctrine_Resource_Exception('Unknown property / related component: '.$key); + } + return $this->_data[$key]; } public function set($key, $value) { - if ($this->_data[$key] != $value) { + if (!$key) { + return; + } + + if (!isset($this->_data[$key]) && $this->getTable()->hasRelation($key)) { + $this->_data[$key] = $this->createRelation($key); + } + + if (!array_key_exists($key, $this->_data)) { + throw new Doctrine_Resource_Exception('Unknown property / related component: '.$key); + } + + if ($this->_data[$key] != $value && !$value instanceof Doctrine_Resource_Record && !$value instanceof Doctrine_Resource_Collection) { $this->_changes[$key] = $value; } $this->_data[$key] = $value; } + public function createRelation($key) + { + $relation = $this->getTable()->getRelation($key); + $class = $relation['class']; + + if ($relation['type'] === Doctrine_Relation::ONE) { + $return = new $class(false); + $table = $return->getTable(); + $returnRelation = $table->getRelationByClassName(get_class($this)); + + if ($returnRelation) { + $returnClass = new $returnRelation['class'](false); + + $return->set($returnRelation['alias'], $returnClass); + } + } else { + $return = new Doctrine_Resource_Collection($class); + $return->setParent($this); + } + + return $return; + } + public function count() { return count($this->_data); @@ -108,8 +154,45 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count return new ArrayIterator($this->_data); } + public function sameAs(Doctrine_Resource_Record $record) + { + // If we have same class name + if (get_class($this) == get_class($record)) { + + // If we have 2 records that exist and are persistant + if ($record->exists() && $this->exists()) { + if ($record->identifier() === $this->identifier()) { + return true; + } else { + return false; + } + // If we have unsaved records then lets compare the data + } else { + if ($record->toArray(false) === $this->toArray(false)) { + return true; + } else { + return false; + } + } + } else { + return false; + } + } + public function getChanges() { + global $gotten; + + if (!$gotten) { + $gotten = array(); + } + + $md5Hash = $this->getMd5Hash(); + + if (!in_array($md5Hash, $gotten)) { + $gotten[] = $md5Hash; + } + $array = array(); foreach ($this->_data as $key => $value) { @@ -117,13 +200,13 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count $relation = $this->getTable()->getRelation($key); - if ($relation['type'] === Doctrine_Relation::ONE) { - if ($this->_data[$key]->hasChanges()) { - $array[$key] = $this->_data[$key]->getChanges(); + if ($value instanceof Doctrine_Resource_Record) { + if ($value->hasChanges() && !in_array($value->getMd5Hash(), $gotten)) { + $array[$key] = $value->getChanges(); } - } else { - foreach ($this->_data[$key] as $key2 => $record) { - if ($record->hasChanges()) { + } else if($value instanceof Doctrine_Resource_Collection) { + foreach ($value as $key2 => $record) { + if ($record->hasChanges() && !in_array($record->getMd5Hash(), $gotten)) { $array[$key][$record->getModel() . '_' .$key2] = $record->getChanges(); } } @@ -160,9 +243,9 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count $response = $request->execute(); - $array = Doctrine_Parser::load($response, $format); + $this->_data = $request->hydrate(array($response), $this->_model, array($this))->getFirst()->_data; - $this->_data = $request->hydrate(array($array), $this->_model)->getFirst()->_data; + $this->clearChanges(); } public function delete() @@ -180,7 +263,9 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count public function getTable() { - return $this->_table; + $model = $this->_model; + + return Doctrine_Resource_Client::getInstance()->getTable($model); } public function getModel() @@ -219,20 +304,38 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count return true; } - public function toArray() + public function toArray($deep = false) { + global $gotten; + + if (!$gotten) { + $gotten = array(); + } + + $md5Hash = $this->getMd5Hash(); + + if (!in_array($md5Hash, $gotten)) { + $gotten[] = $md5Hash; + } + $array = array(); foreach ($this->_data as $key => $value) { - if ($this->getTable()->hasRelation($key) && $value instanceof Doctrine_Resource_Collection) { - if ($value->count() > 0) { - $array[$key] = $value->toArray(); - } - } else if ($this->getTable()->hasRelation($key) && $value instanceof Doctrine_Resource_Record) { - if ($value->exists() || $value->hasChanges()) { - $array[$key] = $value->toArray(); - } + if ($deep && $this->getTable()->hasRelation($key)) { + if ($value instanceof Doctrine_Resource_Collection) { + if ($value->count() > 0) { + foreach ($value as $key2 => $record) { + if (($record->exists() || $record->hasChanges()) && !in_array($record->getMd5Hash(), $gotten)) { + $array[$key][get_class($record) . '_' . $key2] = $record->toArray($deep); + } + } + } + } else if ($value instanceof Doctrine_Resource_Record) { + if (($value->exists() || $value->hasChanges()) && !in_array($value->getMd5Hash(), $gotten)) { + $array[$key] = $value->toArray($deep); + } + } } else if (!$this->getTable()->hasRelation($key) && $this->getTable()->hasColumn($key)) { $array[$key] = $value; } @@ -240,4 +343,9 @@ class Doctrine_Resource_Record extends Doctrine_Resource_Access implements Count return $array; } -} + + public function getMd5Hash() + { + return md5(serialize($this->_data)); + } +} \ No newline at end of file diff --git a/lib/Doctrine/Resource/Request.php b/lib/Doctrine/Resource/Request.php index 10238ede4..87c3204cd 100644 --- a/lib/Doctrine/Resource/Request.php +++ b/lib/Doctrine/Resource/Request.php @@ -59,28 +59,67 @@ class Doctrine_Resource_Request extends Doctrine_Resource_Params curl_close($ch); - return $response; - } - - public function hydrate(array $array, $model, $passedKey = null) - { - if (empty($array)) { - return false; + $array = array(); + + if ($response) { + $array = Doctrine_Parser::load($response, $this->getConfig()->get('format')); } + if (isset($array['error'])) { + throw new Doctrine_Resource_Exception($array['error']); + } + + return $array; + } + + public function hydrate(array $array, $model, $records = array()) + { $collection = new Doctrine_Resource_Collection($model); - foreach ($array as $record) { - $r = new $model(); - + foreach ($array as $recordKey => $record) { + if (isset($records[$recordKey])) { + $r = $records[$recordKey]; + } else { + $r = new $model(false); + } + foreach ($record as $key => $value) { if ($r->getTable()->hasRelation($key) && !empty($value)) { $relation = $r->getTable()->getRelation($key); if ($relation['type'] === Doctrine_Relation::MANY) { - $r->set($key, $this->hydrate($value, $relation['class'], $key)); + $relationCollection = $this->hydrate($value, $relation['class']); + $relationCollection->setParent($r); + + foreach ($relationCollection as $relationRecord) { + $relationTable = $relationRecord->getTable(); + + if ($relation = $relationTable->getRelationByClassName($model)) { + if ($relation['type'] === Doctrine_Relation::ONE) { + $relationRecord->set($relation['alias'], $r); + $relationRecord->clearChanges(); + } else { + $coll = new Doctrine_Resource_Collection($relation['class']); + $coll[] = $r; + + $relationRecord->set($relation['alias'], $coll); + } + + $relationRecord->clearChanges(); + } + } + + $r->set($key, $relationCollection); } else { - $r->set($key, $this->hydrate(array($value), $relation['class'], $key)->getFirst()); + $relationRecord = $this->hydrate(array($value), $relation['class'])->getFirst(); + $relationTable = $relationRecord->getTable(); + + if ($relation = $relationTable->getRelationByClassName($model)) { + $relationRecord->set($relation['alias'], $r); + $relationRecord->clearChanges(); + } + + $r->set($key, $relationRecord); } } else if($r->getTable()->hasColumn($key)) { $r->set($key, $value); diff --git a/lib/Doctrine/Resource/Server.php b/lib/Doctrine/Resource/Server.php index 16bbd9701..ed6762d9c 100644 --- a/lib/Doctrine/Resource/Server.php +++ b/lib/Doctrine/Resource/Server.php @@ -141,12 +141,25 @@ class Doctrine_Resource_Server extends Doctrine_Resource if ($result) { return Doctrine_Parser::dump($result, $format); } else { - return false; + return null; } } public function run($request) { - echo $this->execute($request); + try { + $result = $this->execute($request); + + echo $result; + } catch(Exception $e) { + echo $this->exception($e); + } + } + + public function exception($e) + { + $error = array('error' => $e->getMessage()); + + return Doctrine_Parser::dump($error); } } \ No newline at end of file diff --git a/lib/Doctrine/Resource/Table.php b/lib/Doctrine/Resource/Table.php index 72907794f..5d9380e7a 100644 --- a/lib/Doctrine/Resource/Table.php +++ b/lib/Doctrine/Resource/Table.php @@ -48,6 +48,7 @@ class Doctrine_Resource_Table if (isset($schema['relations'][$model]) && $schema['relations'][$model]) { $this->_schema['relations'] = $schema['relations'][$model]; + $this->_schema['schema']['relations'] = $this->_schema['relations']; } } @@ -61,6 +62,11 @@ class Doctrine_Resource_Table return $this->_schema['relations']; } + public function getColumns() + { + return $this->_schema['columns']; + } + public function getConfig($key = null) { return Doctrine_Resource_Client::getInstance()->getConfig($key); @@ -85,7 +91,9 @@ class Doctrine_Resource_Table $query = new Doctrine_Resource_Query(); $query->from($model)->where($where)->limit(1); - return $query->execute()->getFirst(); + $result = $query->execute(); + + return $result->getFirst(); } public function hasColumn($name) @@ -111,4 +119,35 @@ class Doctrine_Resource_Table return $this->_schema['relations'][$name]; } } + + public function getRelationByClassName($name) + { + $relations = $this->getRelations(); + + foreach ($relations as $relation) { + if ($relation['class'] === $name) { + return $relation; + } + } + + return false; + } + + public function getIdentifier() + { + $identifier = array(); + + $schema = $this->getSchema(); + $columns = $schema['columns']; + + if (isset($columns) && is_array($columns)) { + foreach ($columns as $name => $column) { + if ($column['primary'] == true) { + $identifier[$name] = $name; + } + } + } + + return $identifier; + } } \ No newline at end of file diff --git a/models/User.php b/models/User.php index 781cf783f..16748292e 100644 --- a/models/User.php +++ b/models/User.php @@ -16,6 +16,11 @@ class User extends Entity 'foreign' => 'address_id', 'refClass' => 'EntityAddress', )); + $this->hasMany('Address as Addresses', array( + 'local' => 'user_id', + 'foreign' => 'address_id', + 'refClass' => 'EntityAddress', + )); $this->hasMany('Album', array('local' => 'id', 'foreign' => 'user_id')); $this->hasMany('Book', array('local' => 'id', 'foreign' => 'user_id')); $this->hasMany('Group', array( diff --git a/playground/data.php b/playground/data.php index 3bdd8b583..f70efbe04 100644 --- a/playground/data.php +++ b/playground/data.php @@ -16,6 +16,8 @@ $users[0]->name = 'zYne'; $users[0]['Email']->address = 'zYne@example.com'; $users[0]['Phonenumber'][0]->phonenumber = '123 123'; +$users[0]['Address'][0]->address = '112 2nd ave'; + $users[1]->name = 'Arnold Schwarzenegger'; $users[1]->Email->address = 'arnold@example.com'; $users[1]['Phonenumber'][0]->phonenumber = '123 123'; diff --git a/playground/index.php b/playground/index.php index 44ac6415a..7f2629661 100644 --- a/playground/index.php +++ b/playground/index.php @@ -21,104 +21,54 @@ if ($action == 'server') { // Instantiate a new client $client = Doctrine_Resource_Client::getInstance($url, $config); + $query = new Doctrine_Resource_Query(); + $users = $query->from('User u, u.Group g')->execute(); + + print_r($users->toArray(true)); + + /* + $group = new Group(); + $group->name = 'Jon'; + $group->save(); + + print_r($group->toArray()); + */ + + //$client->printSchema(); + + /* // Retrieve a models table object $table = $client->getTable('User'); - // Find record by identifier - $user = $table->find(4); - - // 2 ways to create queries - $query = new Doctrine_Resource_Query(); - $query->from('User u, u.Phonenumber p')->limit(2); - - // returns users - $users = $query->execute(); - - print_r($users->toArray()); - - /* - Array - ( - [User_0] => Array - ( - [id] => 4 - [name] => zYne - [loginname] => - [password] => - [type] => 0 - [created] => - [updated] => - [email_id] => 1 - [Phonenumber] => Array - ( - [Phonenumber_0] => Array - ( - [id] => 2 - [phonenumber] => 123 123 - [entity_id] => 4 - ) - - ) - - ) - - [User_1] => Array - ( - [id] => 5 - [name] => Arnold Schwarzenegger - [loginname] => - [password] => - [type] => 0 - [created] => - [updated] => - [email_id] => 2 - [Phonenumber] => Array - ( - [Phonenumber_0] => Array - ( - [id] => 3 - [phonenumber] => 123 123 - [entity_id] => 5 - ) - - [Phonenumber_1] => Array - ( - [id] => 4 - [phonenumber] => 456 456 - [entity_id] => 5 - ) - - [Phonenumber_2] => Array - ( - [id] => 5 - [phonenumber] => 789 789 - [entity_id] => 5 - ) - - ) - - ) - - ) - */ - $user = new User(); - $user->name = 'Jonathan H. Wage'; + $user->name = 'Jon Wage'; + + $user->Email->address = 'jonwage@gmail.com'; + + $phone = $user->Phonenumber[0]; + $phone->phonenumber = '555-5555'; + + $phone = $user->Phonenumber[1]; + $phone->phonenumber = '555-55555'; + + $user->Phonenumber[2]->phonenumber = '555'; + + $user->Account->amount = 50.00; + + $user->Account->amount = 25.25; + + $address = $user->Address[0]; + + $address->address = '112 2nd Ave North'; + + $album = $user->Album[0]; + $album->name = 'test album'; + + $song = $album->Song[0]; + $song->title = 'test author'; + $user->save(); - print_r($user->toArray()); - - /* - Array - ( - [id] => 12 - [name] => Jonathan H. Wage - [loginname] => - [password] => - [type] => 0 - [created] => - [updated] => - [email_id] => - ) + print_r($user->toArray(true)); */ } \ No newline at end of file