http://phing.info/

Source Code Coverage

Designed for use with PHPUnit2, Xdebug and Phing.

Methods: 19 LOC: 396 Statements: 116

Source file Statements Methods Total coverage
Entity.php 94.0% 100.0% 94.8%
   
1
<?php
2
/**
3
 * Xyster Framework
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://www.opensource.org/licenses/bsd-license.php
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to xyster@devweblog.org so we can send you a copy immediately.
14
 *
15
 * @category  Xyster
16
 * @package   Xyster_Orm
17
 * @copyright Copyright (c) 2007 Irrational Logic (http://devweblog.org)
18
 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
19
 * @version   $Id: Entity.php 114 2007-10-06 19:31:13Z doublecompile $
20
 */
21
/**
22
 * A data entity: the basic data unit of the ORM package
23
 *
24
 * @category  Xyster
25
 * @package   Xyster_Orm
26
 * @copyright Copyright (c) 2007 Irrational Logic (http://devweblog.org)
27
 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
28
 */
29
class Xyster_Orm_Entity
30
{
31
    /**
32
     * The "base" values from object instantiation
33
     *
34
     * @var array
35
     */
36
    protected $_base = array();
37
38
    /**
39
     * For quick modification checking
40
     *
41
     * @var boolean
42
     */
43
    protected $_dirty = false;
44
45
    /**
46
     * Related entities or sets
47
     *
48
     * @var array
49
     */
50
    protected $_related = array();
51
52
    /**
53
     * The entity values
54
     *
55
     * @var array
56
     */
57
    protected $_values = array();
58
59
    /**
60
     * Entity meta-data (fields, relations, etc.)
61
     *
62
     * @var Xyster_Orm_Entity_Meta[]
63
     */
64
    static private $_meta = array();
65
66
    /**
67
     * Creates a new entity
68
     *
69
     * @param array $values Values for the entity
70
     */
71
    public function __construct( array $values = null )
72
    {
73 104
        if (! $this->_getMeta() instanceof Xyster_Orm_Entity_Meta ) {
74 0
            require_once 'Xyster/Orm/Entity/Exception.php';
75 0
            throw new Xyster_Orm_Entity_Exception('The metadata for ' . get_class($this) . 'has not been setup');
76 0
        }
77
78 104
        foreach( $this->_getMeta()->getFieldNames() as $name ) {
79 104
            $this->_values[$name] = null;
80 104
        }
81
82 104
        if ( $values ) {
83 89
            $this->import($values);
84 89
        }
85
    }
86
87
    /**
88
     * Adds an entity meta information object
89
     *
90
     * This shouldn't be called except by the Xyster_Orm_Mapper
91
     *
92
     * @param Xyster_Orm_Entity_Meta $meta
93
     */
94
    static public function setMeta( Xyster_Orm_Entity_Meta $meta )
95
    {
96 214
        self::$_meta[ $meta->getEntityName() ] = $meta;
97
    }
98
99
    /**
100
     * Overloader for getting/setting linked properties
101
     *
102
     * @param string $name  The method name
103
     * @param array $args  Any arguments used
104
     * @magic
105
     * @return mixed  The result of the method
106
     */
107
    public function __call( $name, array $args )
108
    {
109 34
        $action = strtolower(substr($name, 0, 3));
110 34
        $field = strtolower($name[3]) . substr($name, 4);
111 34
        if ( array_key_exists($field, $this->_values) ) {
112 31
            if ( $action == 'get' ) {
113 1
                return $this->_values[$field];
114 30
            } else if ( $action == 'set' ) {
115 30
                $this->_setField($field, $args[0]);
116 30
            }
117 30
        } else {
118 15
            if ( $action == 'get' ) {
119 1
                return $this->_getRelated($field);
120 14
            } else if ( $action == 'set' ) {
121 14
                $this->_setRelated($field, $args[0]);
122 12
            }
123
        }
124
    }
125
126
    /**
127
     * Overloader for getting fields
128
     *
129
     * @magic
130
     * @param string $name
131
     * @return mixed The value of the field
132
     * @throws Xyster_Orm_Entity_Exception if the field is invalid
133
     */
134
    public function __get( $name )
135
    {
136 55
        $isField = array_key_exists($name, $this->_values);
137 55
        if ( !$isField && !$this->_getMeta()->isRelation($name) ) {
138 1
            require_once 'Xyster/Orm/Entity/Exception.php';
139 1
            throw new Xyster_Orm_Entity_Exception("'" . $name . "' is not a valid field or relation name");
140 0
        }
141 54
        return ( $isField ) ? $this->_values[$name] : $this->_getRelated($name);
142
    }
143
144
    /**
145
     * Overloader for setting fields
146
     *
147
     * @magic
148
     * @param string $name The field name
149
     * @param mixed $value The field value
150
     * @throws Xyster_Orm_Entity_Exception if the field is invalid
151
     */
152
    public function __set( $name, $value )
153
    {
154 32
        $this->{'set'.ucfirst($name)}( $value );
155
    }
156
157
    /**
158
     * Gets the original values of the entity
159
     *
160
     * @return array
161
     */
162
    public function getBase()
163
    {
164 16
        return $this->_base;
165
    }
166
167
    /**
168
     * Gets the fields that have been changed since the entity was created
169
     *
170
     * @return array
171
     */
172
    public function getDirtyFields()
173
    {
174 7
        if ( !$this->_base ) {
175 1
            return $this->_values;
176 0
        }
177 6
        return array_diff_assoc($this->_values, $this->_base);
178
    }
179
180
    /**
181
     * Gets the primary key of the entity
182
     *
183
     * @param boolean $base True to return the original primary key (if changed)
184
     * @return mixed An array or scalar key value
185
     */
186
    public function getPrimaryKey( $base = false )
187
    {
188 76
        return array_intersect_key((!$base ? $this->_values : $this->_base),
189 76
            array_flip($this->_getMeta()->getPrimary()));
190
    }
191
192
    /**
193
     * Gets the primary key of the entity as a Xyster_Data_Criterion
194
     *
195
     * @param boolean $base True to return the original primary key (if changed)
196
     * @return Xyster_Data_Criterion The primary key
197
     */
198
    public function getPrimaryKeyAsCriterion( $base = false )
199
    {
200 18
        $key = $this->getPrimaryKey($base);
201
202
        // build a criterion object based on the primary key(s)
203 18
        $criteria = null;
204 18
        foreach( $key as $name => $value ) {
205 18
            require_once 'Xyster/Data/Expression.php';
206 18
            $thiskey = Xyster_Data_Expression::eq($name, $value);
207 18
            if ( !$criteria ) {
208 18
                $criteria = $thiskey;
209 18
            } else if ( $criteria instanceof Xyster_Data_Expression ) {
210 4
                require_once 'Xyster/Data/Junction.php';
211 4
                $criteria = Xyster_Data_Junction::all($criteria, $thiskey);
212 4
            } else if ( $criteria instanceof Xyster_Data_Junction ) {
213 3
                $criteria->add($thiskey);
214 3
            }
215 18
        }
216
217 18
        return $criteria;
218
    }
219
220
    /**
221
     * Imports the values in the array into the corresponding fields
222
     *
223
     * @param array $values
224
     */
225
    public function import( array $values )
226
    {
227 90
        foreach( array_keys($this->_values) as $field ) {
228 90
            $this->_values[$field] = array_key_exists($field, $values) ?
229 90
                $values[$field] : null;
230 90
        }
231 90
        $this->_base = $this->_values;
232
    }
233
234
    /**
235
     * Determines whether or not this entity has changed values since creation
236
     *
237
     * @return boolean Whether this entity has changed
238
     */
239
    public function isDirty()
240
    {
241 10
        return $this->_dirty;
242
    }
243
244
    /**
245
     * Checks whether a related entity or set has been loaded
246
     *
247
     * @param string $name The name of the relation
248
     * @return boolean true if the relation has been loaded
249
     * @throws Xyster_Orm_Exception if the relationship name is invalid
250
     */
251
    public function isLoaded( $name )
252
    {
253 11
        $this->_getMeta()->getRelation($name); // to test validity
254 11
	    return array_key_exists($name, $this->_related);
255
    }
256
257
    /**
258
     * Sets the entity as dirty or clean
259
     *
260
     * This is only used by the transactional layer or associated collections to
261
     * notify changes in an entity's state.  You shouldn't call this method
262
     * directly.
263
     *
264
     * @param boolean $dirty Whether the entity should be set dirty
265
     */
266
    public function setDirty( $dirty = true )
267
    {
268 13
        $this->_dirty = $dirty;
269
    }
270
271
    /**
272
     * Returns an array copy of the entity
273
     *
274
     * @return array The entity values
275
     */
276
    public function toArray()
277
    {
278 12
        return $this->_values;
279
    }
280
281
    /**
282
     * Returns a string value of this entity
283
     *
284
     * @magic
285
     * @return string
286
     */
287
    public function __toString()
288
    {
289 7
        $string = get_class($this) . ' [';
290 7
        $first = true;
291 7
        foreach( $this->_values as $name => $value ) {
292 7
            if ( !$first ) {
293 7
                $string .= ',';
294 7
            }
295 7
            $string .= $name . '=' . $value;
296 7
            $first = false;
297 7
        }
298 7
        return $string . ']';
299
    }
300
301
    /**
302
     * Gets a related property
303
     *
304
     * @param string $name  The name of the property
305
     * @return mixed  The related Xyster_Orm_Entity or Xyster_Orm_Set
306
     * @throws Xyster_Orm_Exception if the property name is invalid
307
     */
308
    protected function _getRelated( $name )
309
    {
310 16
        if ( !array_key_exists($name, $this->_related) ) {
311 12
            $this->_related[$name] = $this->_getMeta()->getRelation($name)->load($this);
312 12
        }
313 16
        return $this->_related[$name];
314
    }
315
316
    /**
317
     * The base method for setting fields
318
     *
319
     * If overriding this method, make sure to call the parent or else the
320
     * entity won't mark itself dirty.
321
     *
322
     * @param string $name
323
     * @param mixed $value
324
     */
325
    protected function _setField( $name, $value )
326
    {
327 30
        $this->_dirty = true;
328 30
        $this->_values[$name] = $value;
329
    }
330
331
    /**
332
     * Sets a linked property and registers the entity as dirty
333
     *
334
     * @param string $name  The name of the property
335
     * @param mixed $value The new property value
336
     * @throws Xyster_Orm_Exception if the property name is invalid
337
     * @throws Xyster_Orm_Exception if the value is incorrect for the property
338
     */
339
    protected function _setRelated( $name, $value )
340
    {
341 14
        $info = $this->_getMeta()->getRelation($name);
342 14
        $class = $info->getTo();
343
344 14
        if ( !$info->isCollection() ) {
345 13
            if ( $value !== null && ! $value instanceof $class ) {
346 1
                require_once 'Xyster/Orm/Exception.php';
347 1
                throw new Xyster_Orm_Exception("'" . $name . "' must be an instance of '" . $class . "'");
348 0
            }
349 12
        } else {
350 2
            $setClass = get_class($this->_getMeta()->getMapperFactory()->get($class)->getSet());
351 2
            if (! $value instanceof $setClass ) {
352 1
                require_once 'Xyster/Orm/Exception.php';
353 1
                throw new Xyster_Orm_Exception("'" . $name . "' must be an instance of '" . $setClass . "'");
354 0
            }
355
        }
356
357 12
        if ( $info->isCollection() ) {
358
359 1
            $value->relateTo($info, $this);
360
361 12
        } else if ( $value === null ) {
362
363 2
            $fkeyNames = $info->getId();
364 2
            foreach( $fkeyNames as $fkeyName ) {
365 2
                $this->{'set'.ucfirst($fkeyName)}(null);
366 2
            }
367
368 12
        } else if ( $value->getPrimaryKey() ) {
369
370 11
            $fkeyNames = $info->getId();
371 11
            $key = $value->getPrimaryKey();
372 11
            $keyNames = array_keys($key);
373 11
            for( $i=0; $i<count($key); $i++ ) {
374 11
                $keyValue = $key[ $keyNames[$i] ];
375 11
                $fkeyName = $fkeyNames[$i];
376 11
                $this->{'set'.ucfirst($fkeyName)}($keyValue);
377 11
            }
378
379 11
        }
380
381 12
        $this->_related[$name] = $value;
382 12
        $this->_dirty = true;
383
    }
384
385
    /**
386
     * Gets the entity meta
387
     *
388
     * @return Xyster_Orm_Entity_Meta
389
     */
390
    protected function _getMeta()
391
    {
392 106
        $class = get_class($this);
393 106
        return array_key_exists($class, self::$_meta) ?
394 106
            self::$_meta[$class] : null;
395
    }
396
}


Report generated at 2007-10-08T19:32:23-05:00