Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 395 lines (362 sloc) 11.534 kb
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
1 <?php
2 /**
3 * Lithium: the most rad php framework
4 *
4f1a9c0 @nateabele Updating copyright year.
nateabele authored
5 * @copyright Copyright 2011, 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
133 /**
134 * Overloading for reading inaccessible properties.
135 *
136 * @param string $name Property name.
137 * @return mixed Result.
138 */
139 public function &__get($name) {
140 if (isset($this->_relationships[$name])) {
141 return $this->_relationships[$name];
142 }
39e131a @nateabele Updating CRUD integration test, and fixing CRUD operations for CouchD…
nateabele authored
143 if (isset($this->_updated[$name])) {
144 return $this->_updated[$name];
145 }
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
146 if (isset($this->_data[$name])) {
147 return $this->_data[$name];
148 }
a39b648 @nateabele Stripping out more dead and refactored code.
nateabele authored
149 $null = null;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
150 return $null;
151 }
152
153 /**
154 * Overloading for writing to inaccessible properties.
155 *
156 * @param string $name Property name.
157 * @param string $value Property value.
158 * @return mixed Result.
159 */
b51972c @nateabele Beginning refactoring of... stuff.
nateabele authored
160 public function __set($name, $value = null) {
161 if (is_array($name) && !$value) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
162 return array_map(array(&$this, '__set'), array_keys($name), array_values($name));
b51972c @nateabele Beginning refactoring of... stuff.
nateabele authored
163 }
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
164 $this->_updated[$name] = $value;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
165 }
166
167 /**
168 * Overloading for calling `isset()` or `empty()` on inaccessible properties.
169 *
170 * @param string $name Property name.
171 * @return mixed Result.
172 */
173 public function __isset($name) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
174 return isset($this->_data[$name]) || isset($this->_updated[$name]);
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
175 }
176
177 /**
178 * Magic method that allows calling of model methods on this record instance, i.e.:
179 * {{{
180 * $record->validates();
181 * }}}
182 *
183 * @param string $method
184 * @param array $params
185 * @return mixed
186 */
187 public function __call($method, $params) {
188 if (!($model = $this->_model) || !method_exists($model, $method)) {
583059b @davidpersson Adding and replacing ticks/quotes with backticks in error and excepti…
davidpersson authored
189 $message = "No model bound or unhandled method call `{$method}`.";
c219785 @nateabele Implementing nested object support in `Form` helper.
nateabele authored
190 throw new BadMethodCallException($message);
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
191 }
192 array_unshift($params, $this);
a81b5d4 @nateabele Renaming `\data\Model::_instance()` to `\data\Model::_object()`.
nateabele authored
193 $class = $model::invokeMethod('_object');
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
194 return call_user_func_array(array(&$class, $method), $params);
195 }
196
197 /**
198 * Allows several properties to be assigned at once, i.e.:
199 * {{{
200 * $record->set(array('title' => 'Lorem Ipsum', 'value' => 42));
201 * }}}
202 *
203 * @param $values An associative array of fields and values to assign to the `Record`.
204 * @return void
205 */
206 public function set($values) {
207 foreach ($values as $name => $value) {
208 $this->__set($name, $value);
209 }
210 }
211
212 /**
379e432 @nateabele Fixing docblock formatting in `\data\Entity`, and adding a minor fix …
nateabele authored
213 * Access the data fields of the record. Can also access a $named field.
214 *
215 * @param string $name Optionally included field name.
c25e039 @Howard3 Cleaning up PHPDoc @return tags with multiple return types defined.
Howard3 authored
216 * @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
217 */
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
218 public function data($name = null) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
219 if ($name) {
220 return $this->__get($name);
221 }
d9ee039 @Howard3 Document: to(array) now works recursively. Patch by Nate Abele
Howard3 authored
222 return $this->to('array');
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
223 }
224
225 /**
226 * Returns the model which this entity is bound to.
227 *
228 * @return string The fully qualified model class name.
229 */
230 public function model() {
231 return $this->_model;
232 }
233
234 public function schema($field = null) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
235 $schema = array();
236
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
237 switch (true) {
238 case ($this->_schema):
239 $schema = $this->_schema;
240 break;
241 case ($model = $this->_model):
242 $schema = $model::schema();
243 break;
244 }
245 if ($field) {
318a6dd @nateabele Adding test case for `\data\Entity`.
nateabele authored
246 return isset($schema[$field]) ? $schema[$field] : null;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
247 }
248 return $schema;
249 }
250
251 /**
252 * Access the errors of the record.
253 *
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
254 * @see lithium\data\Entity::$_errors
255 * @param array|string $field If an array, overwrites `$this->_errors`. If a string, and
256 * `$value` is not `null`, sets the corresponding key in `$this->_errors` to `$value`.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
257 * @param string $value Value to set.
c25e039 @Howard3 Cleaning up PHPDoc @return tags with multiple return types defined.
Howard3 authored
258 * @return mixed Either the `$this->_errors` array, or single value from it.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
259 */
260 public function errors($field = null, $value = null) {
261 if ($field === null) {
262 return $this->_errors;
263 }
264 if (is_array($field)) {
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
265 return ($this->_errors = $field);
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
266 }
267 if ($value === null && isset($this->_errors[$field])) {
268 return $this->_errors[$field];
269 }
270 if ($value !== null) {
271 return $this->_errors[$field] = $value;
272 }
273 return $value;
274 }
275
276 /**
277 * A flag indicating whether or not this record exists.
278 *
279 * @return boolean `True` if the record was `read` from the data-source, or has been `create`d
280 * and `save`d. Otherwise `false`.
281 */
282 public function exists() {
283 return $this->_exists;
284 }
285
286 /**
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
287 * 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
288 * 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
289 * object. **Do not** call this method if you intend to update the database's copy of the
290 * entity. Instead, see `Model::save()`.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
291 *
ad3ccf3 @nateabele Cleanup and documentation for misc. `\data` classes. Refactored `Docu…
nateabele authored
292 * @see lithium\data\Model::save()
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
293 * @param mixed $id The ID to assign, where applicable.
294 * @param array $data Any additional generated data assigned to the object by the database.
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
295 * @return void
296 */
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
297 public function update($id = null, array $data = array()) {
298 $this->_exists = true;
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
299 $model = $this->_model;
300 $key = array();
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
301
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
302 if ($id && $model) {
303 $key = $model::meta('key');
304 $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
305 }
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
306 $this->_data = ($key + $data + $this->_updated + $this->_data);
307 $this->_updated = array();
308 }
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
309
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
310 /**
311 * Safely (atomically) increments the value of the specified field by an arbitrary value.
312 * Defaults to `1` if no value is specified. Throws an exception if the specified field is
313 * non-numeric.
314 *
a0930f4 @phishy fixed spelling errors
phishy authored
315 * @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
316 * @param string $value The value to increment the field by. Defaults to `1` if this parameter
317 * is not specified.
6cbb2cd @nateabele Fixing misc. QA issues and adding docblocks.
nateabele authored
318 * @return integer Returns the current value of `$field`, based on the value retrieved from the
319 * data source when the entity was loaded, plus any increments applied. Note that it may
320 * 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
321 * @throws UnexpectedValueException Throws an exception when `$field` is set to a non-numeric
322 * type.
323 */
324 public function increment($field, $value = 1) {
325 if (!isset($this->_data[$field])) {
326 return $this->_data[$field] = $value;
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
327 }
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
328 if (!is_numeric($this->_data[$field])) {
329 throw new UnexpectedValueException("Field '{$field}' cannot be incremented.");
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
330 }
379e432 @nateabele Fixing docblock formatting in `\data\Entity`, and adding a minor fix …
nateabele authored
331 $base = isset($this->_updated[$field]) ? $this->_updated[$field] : $this->_data[$field];
332 return $this->_updated[$field] = ($base + $value);
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
333 }
334
335 /**
336 * Decrements a field by the specified value. Works identically to `increment()`, but in
337 * reverse.
338 *
339 * @see lithium\data\Entity::increment()
340 * @param string $field The name of the field to decrement.
341 * @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
342 * @return integer Returns the new value of `$field`, after modification.
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
343 */
344 public function decrement($field, $value = 1) {
345 return $this->increment($field, $value * -1);
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
346 }
347
348 /**
349 * Gets the array of fields modified on this entity.
350 *
351 * @return array Returns an array where the keys are entity field names, and the values are
352 * always `true`.
353 */
354 public function modified() {
355 if (!$this->_exists) {
6529811 @pauluswebster Use correct properties for obtaining modified values
pauluswebster authored
356 $keys = array_keys($this->_data + $this->_updated);
357 } else {
358 $keys = array_keys($this->_updated);
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
359 }
6529811 @pauluswebster Use correct properties for obtaining modified values
pauluswebster authored
360 return array_combine($keys, array_fill(0, count($keys), true));
f7ae4c1 @nateabele Refactoring base classes in `\data`, implementing one-to-many relatio…
nateabele authored
361 }
362
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
363 public function export() {
364 return array(
365 'exists' => $this->_exists,
366 'data' => $this->_data,
367 'update' => $this->_updated,
26c2192 @davidpersson QA: Removing trailing comma in arrays, lowercasing some keywords.
davidpersson authored
368 'increment' => $this->_increment
eaa5770 @nateabele Rewriting change-tracking in data entities. Original state and change…
nateabele authored
369 );
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
370 }
371
372 /**
373 * Converts the data in the record set to a different format, i.e. an array.
374 *
375 * @param string $format currently only `array`
376 * @param array $options
377 * @return mixed
378 */
379 public function to($format, array $options = array()) {
380 switch ($format) {
381 case 'array':
d9ee039 @Howard3 Document: to(array) now works recursively. Patch by Nate Abele
Howard3 authored
382 $data = $this->_updated + $this->_data;
4e7d186 @nateabele Fixing array mapping in `Entity` and `Document` classes.
nateabele authored
383 $rel = array_map(function($obj) { return $obj->data(); }, $this->_relationships);
384 $data = array_merge($data, $rel);
385 $result = Collection::toArray($data, $options);
27bd48e @nateabele Adding missing files from last commit.
nateabele authored
386 break;
387 default:
388 $result = $this;
389 break;
390 }
391 return $result;
392 }
393 }
394
1281928 @daschl QA: Misc. Fixes
daschl authored
395 ?>
Something went wrong with that request. Please try again.