Permalink
Browse files

Refactoring base classes in `\data`, implementing one-to-many relatio…

…nship support for MongoDB. Implementing GridFS support in MongoDB. Making `\util\Collection::toArray()` public.
  • Loading branch information...
1 parent c96df6d commit f7ae4c1a1d15624c8c150a13d1d3b898da19b9bc @nateabele nateabele committed Jun 15, 2010
@@ -168,7 +168,7 @@ public function offsetExists($offset) {
* @return object Returns the first `Entity` instance in the set.
*/
public function rewind() {
- $this->_valid = (reset($this->_data) || count($this->_data));
+ $this->_valid = (reset($this->_data) || count($this->_data));
if (!$this->_valid && !$this->_hasInitialized) {
$this->_hasInitialized = true;
@@ -224,6 +224,33 @@ public function map($filter, array $options = array()) {
return parent::map($filter, $options);
}
+ /**
+ * Converts the current state of the data structure to an array.
+ *
+ * @return array Returns the array value of the data in this `Collection`.
+ */
+ public function data() {
+ return $this->to('array');
+ }
+
+ /**
+ * Adds the specified object to the `Collection` instance, and assigns associated metadata to
+ * the added object.
+ *
+ * @param string $offset The offset to assign the value to.
+ * @param mixed $data The entity object to add.
+ * @return mixed Returns the set `Entity` object.
+ */
+ public function offsetSet($offset, $data) {
+ if (is_array($data)) {
+ $class = $this->_classes['entity'];
+ $data = new $class(compact('data'));
+ } else {
+ $data->assignTo($this);
+ }
+ return $this->_data[] = $data;
+ }
+
/**
* Gets the stat or stats associated with this `Collection`.
*
@@ -9,6 +9,8 @@
namespace lithium\data;
use \RuntimeException;
+use \lithium\data\Source;
+use \lithium\util\Collection as Col;
/**
* `Entity` class. Represents data such as a row or document in a database. Entities have fields
@@ -22,18 +24,10 @@ class Entity extends \lithium\core\Object {
protected $_model = null;
/**
- * Associative array of the records fields with values
+ * Associative array of the entity's fields and values.
*/
protected $_data = array();
- /**
- * If this object is chained off of an originally queried object, contains an instance of
- * `Relationship` defining the relationship from the origin object to this one.
- *
- * @var object
- */
- protected $_relationship = null;
-
/**
* An array containing all related records and recordsets, keyed by relationship name, as
* defined in the bound model class.
@@ -279,25 +273,53 @@ public function exists() {
}
/**
- * Called after a `Record` is saved. Updates the object's internal state to reflect the
+ * Called after an `Entity` is saved. Updates the object's internal state to reflect the
* corresponding database record, and sets the `Record`'s primary key, if this is a
* newly-created object.
*
- * @param $id The ID to assign, where applicable.
+ * @param mixed $id The ID to assign, where applicable.
+ * @param array $data Any additional generated data assigned to the object by the database.
* @return void
*/
- public function update($id = null, $data = array()) {
- if ($id) {
- $id = (array) $id;
- $model = $this->_model;
- foreach ((array) $model::meta('key') as $i => $key) {
- $this->_data[$key] = $id[$i];
- }
- foreach ($data as $key => $value) {
- $this->_data[$key] = $value;
+ public function update($id = null, array $data = array()) {
+ $this->_modified = array();
+ $this->_exists = true;
+
+ if (!$id) {
+ return;
+ }
+
+ $model = $this->_model;
+ $key = $model::meta('key');
+
+ if (is_array($key)) {
+ foreach ($key as $i => $k) {
+ $this->_data[$k] = $id[$i];
}
+ } else {
+ $this->_data[$key] = $id;
}
- $this->_exists = true;
+ foreach ($data as $key => $value) {
+ $this->_data[$key] = $value;
+ }
+ }
+
+ /**
+ * Gets the array of fields modified on this entity.
+ *
+ * @return array Returns an array where the keys are entity field names, and the values are
+ * always `true`.
+ */
+ public function modified() {
+ if (!$this->_exists) {
+ $keys = array_keys($this->_data);
+ return array_combine($keys, array_fill(0, count($keys), true));
+ }
+ return $this->_modified;
+ }
+
+ public function export(Source $dataSource, array $options = array()) {
+ return array_intersect_key($this->_data, $this->_modified);
}
/**
@@ -324,7 +346,7 @@ public function assignTo($parent, array $config = array()) {
public function to($format, array $options = array()) {
switch ($format) {
case 'array':
- $result = $this->_data;
+ $result = Col::toArray($this->_data);
break;
default:
$result = $this;
@@ -279,7 +279,7 @@ class Model extends \lithium\core\StaticObject {
* extended but not directly interacted with) must be present in this list. Models can declare
* themselves as base models using the following code:
* {{{
- * public function __init() {
+ * public static function __init() {
* static::_isBase(__CLASS__, true);
* parent::__init();
* }
@@ -422,12 +422,13 @@ public static function __callStatic($method, $params) {
public static function find($type, array $options = array()) {
$self = static::_instance();
$classes = $self->_classes;
+ $finder = array();
$defaults = array(
'conditions' => null, 'fields' => null, 'order' => null, 'limit' => null, 'page' => 1
);
- if ($type != 'all' && !isset($self->_finders[$type]) && is_scalar($type)) {
+ if ($type != 'all' && is_scalar($type) && !isset($self->_finders[$type])) {
$options['conditions'] = array($self->_meta['key'] => $type);
$type = 'first';
}
@@ -443,7 +444,9 @@ public static function find($type, array $options = array()) {
$connection = $self::invokeMethod('_connection');
return $connection->read(new $query(array('type' => 'read') + $options), $options);
};
- $finder = isset($self->_finders[$type]) ? array($self->_finders[$type]) : array();
+ if (is_string($type) && isset($self->_finders[$type])) {
+ $finder = is_callable($self->_finders[$type]) ? array($self->_finders[$type]) : array();
+ }
return static::_filter(__FUNCTION__, $params, $filter, $finder);
}
@@ -613,7 +616,7 @@ public static function hasField($field) {
* {{{
* $post = Post::create(array("title" => "New post"));
* echo $post->title; // echoes "New post"
- * $post->save();
+ * $success = $post->save();
* }}}
*
* @param array $data Any data that this record should be populated with initially.
@@ -9,24 +9,18 @@
namespace lithium\data\collection;
use \Iterator;
+use \lithium\data\Source;
+use \lithium\util\Collection;
class DocumentSet extends \lithium\data\Collection {
- /**
- * An array containing all related documents, keyed by relationship name, as defined in the
- * bound model class.
- *
- * @var array
- */
- protected $_relationships = array();
-
/**
* The class dependencies for `Document`.
*
* @var array
*/
protected $_classes = array(
- 'entity' => '\lithium\data\entity\Document',
+ 'entity' => 'lithium\data\entity\Document',
'set' => __CLASS__
);
@@ -68,7 +62,6 @@ public function __set($name, $value = null) {
$value = $this->_relation('set', $name, $value);
}
$this->_data[$name] = $value;
- $this->_modified[$name] = true;
}
/**
@@ -106,7 +99,9 @@ public function __unset($name) {
* @return void
*/
public function set($values) {
- $this->__set($values);
+ foreach ($values as $key => $val) {
+ $this[$key] = $val;
+ }
}
/**
@@ -117,7 +112,22 @@ public function set($values) {
* @return mixed Returns either a sub-object in the document, or a scalar field value.
*/
public function offsetGet($offset) {
- return $this->__get($offset);
+ $data = null;
+ $null = null;
+
+ if (!isset($this->_data[$offset]) && !$data = $this->_populate(null, $offset)) {
+ return $null;
+ }
+ $data = $data ?: $this->_data[$offset];
+
+ if (is_a($data, $this->_classes['entity'])) {
+ return $data;
+ }
+
+ if ($this->_isComplexType($data)) {
+ $this->_data[$offset] = $this->_relation('entity', $offset, $this->_data[$offset]);
+ }
+ return $this->_data[$offset];
}
/**
@@ -126,7 +136,21 @@ public function offsetGet($offset) {
* @return object Returns the first `Document` object instance in the collection.
*/
public function rewind() {
- return ($entity = parent::rewind()) ? $entity : $this->__get(key($this->_data));
+ $data = parent::rewind();
+ $key = key($this->_data);
+
+ if (is_a($data, $this->_classes['entity'])) {
+ return $data;
+ }
+
+ if ($this->_isComplexType($data)) {
+ $this->_data[$key] = $this->_relation('entity', $key, $this->_data[$key]);
+ }
+ return isset($this->_data[$key]) ? $this->_data[$key] : null;
+ }
+
+ public function current() {
+ return $this->offsetGet(key($this->_data));
}
/**
@@ -146,43 +170,14 @@ public function next() {
$this->_valid = true;
}
$this->_valid = $this->_valid ?: !is_null($this->_populate());
- return $this->_valid ? $this->__get(key($this->_data)) : null;
+ return $this->_valid ? $this->offsetGet(key($this->_data)) : null;
}
- /**
- * PHP magic method used when accessing fields as document properties, i.e. `$document->_id`.
- *
- * @param $name The field name, as specified with an object property.
- * @return mixed Returns the value of the field specified in `$name`, and wraps complex data
- * types in sub-`Document` objects.
- */
- public function &__get($name) {
- $data = null;
- $null = null;
-
- if (strpos($name, '.')) {
- $current = $this;
- $path = explode('.', $name);
- $length = count($path) - 1;
-
- foreach ($path as $i => $key) {
- $current =& $current->__get($key);
- if (!$current instanceof Document && $i < $length) {
- return $null;
- }
- }
- return $current;
- }
-
- if (!isset($this->_data[$name]) && !$data = $this->_populate(null, $name)) {
- return $null;
- }
- $data = $data ?: $this->_data[$name];
-
- if ($this->_isComplexType($data) && !$data instanceof \lithium\data\Entity) {
- $this->_data[$name] = $this->_relation('entity', $name, $this->_data[$name]);
- }
- return $this->_data[$name];
+ public function export(Source $dataSource, array $options = array()) {
+ $map = function($doc) use ($dataSource, $options) {
+ return is_array($doc) ? $doc : $doc->export($dataSource, $options);
+ };
+ return array_map($map, $this->_data);
}
/**
@@ -240,23 +235,13 @@ protected function _populate($data = null, $key = null) {
*/
protected function _relation($classType, $key, $data, $options = array()) {
$parent = $this;
- $key = ($key === null) ? count($this->_data) : $key;
- $pathKey = trim("{$this->_pathKey}.{$key}", '.');
-
- if (($key || $key === 0) && $model = $this->_model) {
- foreach ($model::relations() as $name => $relation) {
- if ($relation && ($key === $relation->data('fieldName'))) {
- $model = $relation->data('to');
- break;
- }
- }
- }
+ $model = $this->_model;
if (is_object($data) && $data instanceof Document) {
$data->assignTo($this, compact('model', 'pathKey'));
return $data;
}
- $options += compact('model', 'data', 'parent', 'pathKey');
+ $options += compact('model', 'data', 'parent');
return new $this->_classes[$classType]($options);
}
}
Oops, something went wrong.

0 comments on commit f7ae4c1

Please sign in to comment.