Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 406 lines (371 sloc) 11.9 kb
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
1 <?php
2 /**
3 * Lithium: the most rad php framework
4 *
14de7bf @gwoo Happy 2012!
gwoo authored
5 * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
6 * @license http://opensource.org/licenses/bsd-license.php The BSD License
7 */
8
9 namespace lithium\data;
10
00ce46c @nateabele Implemented core exceptions. Implemented `\core\Libraries::instance()…
nateabele authored
11 use BadMethodCallException;
318a6dd @nateabele Adding test case for `\data\Entity`.
nateabele authored
12 use UnexpectedValueException;
ab41ff6 @nateabele First pass at refactoring SQL relationship support.
nateabele authored
13 use lithium\data\Collection;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
14
15 /**
a93f529 @nateabele Expanding class documentation for `\data\Entity`.
nateabele authored
16 * `Entity` is a smart data object which represents data such as a row or document in a
17 * database. Entities have fields (often known as columns in databases), and track changes to its
18 * fields, as well as associated validation errors, etc.
19 *
20 * The `Entity` class can also be used as a base class for your own custom data objects, and is the
21 * basis for generating forms with the `Form` helper.
22 *
23 * @see lithium\template\helper\Form
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
24 */
25 class Entity extends \lithium\core\Object {
26
27 /**
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
28 * Fully-namespaced class name of model that this record is bound to. Instance methods declared
29 * in the model may be called on the entity. See the `Model` class documentation for more
30 * information.
31 *
32 * @see lithium\data\Model
33 * @see lithium\data\Entity::__call()
34 * @var string
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
35 */
36 protected $_model = null;
37
38 /**
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
39 * Associative array of the entity's fields and values.
39e131a @nateabele Updating CRUD integration test, and fixing CRUD operations for CouchD…
nateabele authored
40 *
41 * @var array
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
42 */
43 protected $_data = array();
44
45 /**
46 * An array containing all related records and recordsets, keyed by relationship name, as
47 * defined in the bound model class.
48 *
49 * @var array
50 */
51 protected $_relationships = array();
52
53 /**
54 * If this record is chained off of another, contains the origin object.
55 *
56 * @var object
57 */
58 protected $_parent = null;
59
60 /**
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
61 * The list of validation errors associated with this object, where keys are field names, and
62 * values are arrays containing one or more validation error messages.
63 *
64 * @see lithium\data\Entity::errors()
65 * @var array
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
66 */
67 protected $_errors = array();
68
69 /**
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
70 * Contains the values of updated fields. These values will be persisted to the backend data
71 * store when the document is saved.
72 *
73 * @var array
74 */
75 protected $_updated = array();
76
77 /**
78 * An array of key/value pairs corresponding to fields that should be updated using atomic
79 * incrementing / decrementing operations. Keys match field names, and values indicate the value
a0930f4 @phishy fixed spelling errors
phishy authored
80 * each field should be incremented or decremented by.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
81 *
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
82 * @see lithium\data\Entity::increment()
83 * @see lithium\data\Entity::decrement()
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
84 * @var array
85 */
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
86 protected $_increment = array();
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
87
88 /**
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
89 * A flag indicating whether or not this entity exists. Set to `false` if this is a
90 * newly-created entity, or if this entity has been loaded and subsequently deleted. Set to
91 * `true` if the entity has been loaded from the database, or has been created and subsequently
92 * saved.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
93 *
94 * @var boolean
95 */
96 protected $_exists = false;
97
98 /**
99 * A local copy of the schema definition. This is the same as `lithium\data\Model::$_schema`,
100 * but can be defined here if this is a one-off object or class used for a single purpose, i.e.
101 * to create a form.
102 *
103 * @var array
104 */
105 protected $_schema = array();
106
107 /**
108 * Auto configuration.
109 *
110 * @var array
111 */
112 protected $_autoConfig = array(
6857c6b @nateabele Data in `\data\Entity` now shows up above related data in calls to `d…
nateabele authored
113 'classes' => 'merge', 'parent', 'schema', 'data',
114 'model', 'exists', 'pathKey', 'relationships'
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
115 );
116
117 /**
118 * Creates a new record object with default values.
119 *
120 * Options defined:
121 * - 'data' _array_: Data to enter into the record. Defaults to an empty array.
122 * - 'model' _string_: Class name that provides the data-source for this record.
123 * Defaults to `null`.
124 *
125 * @param array $config
126 * @return object Record object.
127 */
128 public function __construct(array $config = array()) {
4fa7aa7 @Howard3 Reworking Relationships
Howard3 authored
129 $defaults = array('model' => null, 'data' => array(), 'relationships' => array());
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
130 parent::__construct($config + $defaults);
131 }
132
18b6a8c @nateabele Refactoring MongoDB changeset calculation for update operations, to i…
nateabele authored
133 protected function _init() {
134 parent::_init();
135 $this->_updated = $this->_data;
136 }
137
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
138 /**
139 * Overloading for reading inaccessible properties.
140 *
141 * @param string $name Property name.
142 * @return mixed Result.
143 */
144 public function &__get($name) {
145 if (isset($this->_relationships[$name])) {
146 return $this->_relationships[$name];
147 }
39e131a @nateabele Updating CRUD integration test, and fixing CRUD operations for CouchD…
nateabele authored
148 if (isset($this->_updated[$name])) {
149 return $this->_updated[$name];
150 }
a39b648 @nateabele Stripping out more dead and refactored code.
nateabele authored
151 $null = null;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
152 return $null;
153 }
154
155 /**
156 * Overloading for writing to inaccessible properties.
157 *
158 * @param string $name Property name.
159 * @param string $value Property value.
160 * @return mixed Result.
161 */
b51972c @nateabele Beginning refactoring of... stuff.
nateabele authored
162 public function __set($name, $value = null) {
163 if (is_array($name) && !$value) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
164 return array_map(array(&$this, '__set'), array_keys($name), array_values($name));
b51972c @nateabele Beginning refactoring of... stuff.
nateabele authored
165 }
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
166 $this->_updated[$name] = $value;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
167 }
168
169 /**
170 * Overloading for calling `isset()` or `empty()` on inaccessible properties.
171 *
172 * @param string $name Property name.
173 * @return mixed Result.
174 */
175 public function __isset($name) {
1a0af0e Fix for #384. Check relationships in Entity::_isset().
Marc Ghorayeb authored
176 return isset($this->_updated[$name]) || isset($this->_relationships[$name]);
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
177 }
178
b3b5696 Added test for model instance methods.
Tobias Sandelius authored
179 /**
180 * Magic method that allows calling of model methods on this record instance, i.e.:
181 * {{{
182 * $record->validates();
183 * }}}
184 *
185 * @see lithium\data\Model::instanceMethods
186 * @param string $method
187 * @param array $params
188 * @return mixed
189 */
190 public function __call($method, $params) {
191 if ($model = $this->_model) {
192 $methods = $model::instanceMethods();
a8d8e04 Refactored Entity::__call and some code cleanup.
Tobias Sandelius authored
193 array_unshift($params, $this);
194
b3b5696 Added test for model instance methods.
Tobias Sandelius authored
195 if (method_exists($model, $method)) {
196 $class = $model::invokeMethod('_object');
a8d8e04 Refactored Entity::__call and some code cleanup.
Tobias Sandelius authored
197 return call_user_func_array(array(&$class, $method), $params);
b3b5696 Added test for model instance methods.
Tobias Sandelius authored
198 }
a8d8e04 Refactored Entity::__call and some code cleanup.
Tobias Sandelius authored
199 if (isset($methods[$method]) && is_callable($methods[$method])) {
200 return call_user_func_array($methods[$method], $params);
b3b5696 Added test for model instance methods.
Tobias Sandelius authored
201 }
202 }
203 $message = "No model bound or unhandled method call `{$method}`.";
204 throw new BadMethodCallException($message);
205 }
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
206
207 /**
208 * Allows several properties to be assigned at once, i.e.:
209 * {{{
210 * $record->set(array('title' => 'Lorem Ipsum', 'value' => 42));
211 * }}}
212 *
18b6a8c @nateabele Refactoring MongoDB changeset calculation for update operations, to i…
nateabele authored
213 * @param array $data An associative array of fields and values to assign to this `Entity`
214 * instance.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
215 * @return void
216 */
18b6a8c @nateabele Refactoring MongoDB changeset calculation for update operations, to i…
nateabele authored
217 public function set(array $data) {
218 foreach ($data as $name => $value) {
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
219 $this->__set($name, $value);
220 }
221 }
222
223 /**
379e432 @nateabele Fixing docblock formatting in `\data\Entity`, and adding a minor fix …
nateabele authored
224 * Access the data fields of the record. Can also access a $named field.
225 *
226 * @param string $name Optionally included field name.
c25e039 @Howard3 Cleaning up PHPDoc @return tags with multiple return types defined.
Howard3 authored
227 * @return mixed Entire data array if $name is empty, otherwise the value from the named field.
379e432 @nateabele Fixing docblock formatting in `\data\Entity`, and adding a minor fix …
nateabele authored
228 */
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
229 public function data($name = null) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
230 if ($name) {
231 return $this->__get($name);
232 }
d9ee039 @Howard3 Document: to(array) now works recursively. Patch by Nate Abele
Howard3 authored
233 return $this->to('array');
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
234 }
235
236 /**
237 * Returns the model which this entity is bound to.
238 *
239 * @return string The fully qualified model class name.
240 */
241 public function model() {
242 return $this->_model;
243 }
244
245 public function schema($field = null) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
246 $schema = array();
247
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
248 switch (true) {
249 case ($this->_schema):
250 $schema = $this->_schema;
251 break;
252 case ($model = $this->_model):
253 $schema = $model::schema();
254 break;
255 }
256 if ($field) {
318a6dd @nateabele Adding test case for `\data\Entity`.
nateabele authored
257 return isset($schema[$field]) ? $schema[$field] : null;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
258 }
259 return $schema;
260 }
261
262 /**
263 * Access the errors of the record.
264 *
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
265 * @see lithium\data\Entity::$_errors
266 * @param array|string $field If an array, overwrites `$this->_errors`. If a string, and
267 * `$value` is not `null`, sets the corresponding key in `$this->_errors` to `$value`.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
268 * @param string $value Value to set.
c25e039 @Howard3 Cleaning up PHPDoc @return tags with multiple return types defined.
Howard3 authored
269 * @return mixed Either the `$this->_errors` array, or single value from it.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
270 */
271 public function errors($field = null, $value = null) {
272 if ($field === null) {
273 return $this->_errors;
274 }
275 if (is_array($field)) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
276 return ($this->_errors = $field);
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
277 }
278 if ($value === null && isset($this->_errors[$field])) {
279 return $this->_errors[$field];
280 }
281 if ($value !== null) {
282 return $this->_errors[$field] = $value;
283 }
284 return $value;
285 }
286
287 /**
288 * A flag indicating whether or not this record exists.
289 *
290 * @return boolean `True` if the record was `read` from the data-source, or has been `create`d
291 * and `save`d. Otherwise `false`.
292 */
293 public function exists() {
294 return $this->_exists;
295 }
296
297 /**
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
298 * Called after an `Entity` is saved. Updates the object's internal state to reflect the
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
299 * corresponding database entity, and sets the `Entity` object's key, if this is a newly-created
ad3ccf3 @nateabele Cleanup and documentation for misc. `\data` classes. Refactored `Docu…
nateabele authored
300 * object. **Do not** call this method if you intend to update the database's copy of the
301 * entity. Instead, see `Model::save()`.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
302 *
ad3ccf3 @nateabele Cleanup and documentation for misc. `\data` classes. Refactored `Docu…
nateabele authored
303 * @see lithium\data\Model::save()
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
304 * @param mixed $id The ID to assign, where applicable.
305 * @param array $data Any additional generated data assigned to the object by the database.
b58092f @nateabele Renaming `Entity::update()` to `Entity::sync()` to better reflect fun…
nateabele authored
306 * @param array $options Method options:
307 * - `'materialize'` _boolean_: Determines whether or not the flag should be set
308 * that indicates that this entity exists in the data store. Defaults to `true`.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
309 * @return void
310 */
b58092f @nateabele Renaming `Entity::update()` to `Entity::sync()` to better reflect fun…
nateabele authored
311 public function sync($id = null, array $data = array(), array $options = array()) {
312 $defaults = array('materialize' => true);
313 $options += $defaults;
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
314 $model = $this->_model;
315 $key = array();
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
316
b58092f @nateabele Renaming `Entity::update()` to `Entity::sync()` to better reflect fun…
nateabele authored
317 if ($options['materialize']) {
318 $this->_exists = true;
319 }
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
320 if ($id && $model) {
321 $key = $model::meta('key');
322 $key = is_array($key) ? array_combine($key, $id) : array($key => $id);
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
323 }
18b6a8c @nateabele Refactoring MongoDB changeset calculation for update operations, to i…
nateabele authored
324 $this->_data = $this->_updated = ($key + $data + $this->_updated);
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
325 }
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
326
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
327 /**
328 * Safely (atomically) increments the value of the specified field by an arbitrary value.
329 * Defaults to `1` if no value is specified. Throws an exception if the specified field is
330 * non-numeric.
331 *
a0930f4 @phishy fixed spelling errors
phishy authored
332 * @param string $field The name of the field to be incremented.
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
333 * @param string $value The value to increment the field by. Defaults to `1` if this parameter
334 * is not specified.
6cbb2cd @nateabele Fixing misc. QA issues and adding docblocks.
nateabele authored
335 * @return integer Returns the current value of `$field`, based on the value retrieved from the
336 * data source when the entity was loaded, plus any increments applied. Note that it may
337 * not reflect the most current value in the persistent backend data source.
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
338 * @throws UnexpectedValueException Throws an exception when `$field` is set to a non-numeric
339 * type.
340 */
341 public function increment($field, $value = 1) {
18b6a8c @nateabele Refactoring MongoDB changeset calculation for update operations, to i…
nateabele authored
342 if (!isset($this->_updated[$field])) {
343 return $this->_updated[$field] = $value;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
344 }
18b6a8c @nateabele Refactoring MongoDB changeset calculation for update operations, to i…
nateabele authored
345 if (!is_numeric($this->_updated[$field])) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
346 throw new UnexpectedValueException("Field '{$field}' cannot be incremented.");
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
347 }
18b6a8c @nateabele Refactoring MongoDB changeset calculation for update operations, to i…
nateabele authored
348 return $this->_updated[$field] += $value;
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
349 }
350
351 /**
352 * Decrements a field by the specified value. Works identically to `increment()`, but in
353 * reverse.
354 *
355 * @see lithium\data\Entity::increment()
356 * @param string $field The name of the field to decrement.
357 * @param string $value The value by which to decrement the field. Defaults to `1`.
6cbb2cd @nateabele Fixing misc. QA issues and adding docblocks.
nateabele authored
358 * @return integer Returns the new value of `$field`, after modification.
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
359 */
360 public function decrement($field, $value = 1) {
361 return $this->increment($field, $value * -1);
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
362 }
363
364 /**
365 * Gets the array of fields modified on this entity.
366 *
367 * @return array Returns an array where the keys are entity field names, and the values are
368 * always `true`.
369 */
370 public function modified() {
a0e3f7d @Howard3 Related to #155 - simplifying Entity->modified with more up-to-date s…
Howard3 authored
371 return array_fill_keys(array_keys($this->_updated), true);
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
372 }
373
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
374 public function export() {
375 return array(
376 'exists' => $this->_exists,
377 'data' => $this->_data,
378 'update' => $this->_updated,
26c2192 @davidpersson QA: Removing trailing comma in arrays, lowercasing some keywords.
davidpersson authored
379 'increment' => $this->_increment
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
380 );
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
381 }
382
383 /**
384 * Converts the data in the record set to a different format, i.e. an array.
385 *
386 * @param string $format currently only `array`
387 * @param array $options
388 * @return mixed
389 */
390 public function to($format, array $options = array()) {
391 switch ($format) {
392 case 'array':
18b6a8c @nateabele Refactoring MongoDB changeset calculation for update operations, to i…
nateabele authored
393 $data = $this->_updated;
4e7d186 @nateabele Fixing array mapping in `Entity` and `Document` classes.
nateabele authored
394 $rel = array_map(function($obj) { return $obj->data(); }, $this->_relationships);
dae6dcd @Howard3 Updating entity to concat arrays instead of merging, this makes it mo…
Howard3 authored
395 $data = $rel + $data;
4e7d186 @nateabele Fixing array mapping in `Entity` and `Document` classes.
nateabele authored
396 $result = Collection::toArray($data, $options);
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
397 break;
398 default:
399 $result = $this;
400 break;
401 }
402 return $result;
403 }
404 }
405
1281928 @daschl QA: Misc. Fixes
daschl authored
406 ?>
Something went wrong with that request. Please try again.