http://phing.info/

Source Code Coverage

Designed for use with PHPUnit2, Xdebug and Phing.

Methods: 24 LOC: 773 Statements: 347

Source file Statements Methods Total coverage
Mapper.php 96.8% 100.0% 97.0%
   
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: Mapper.php 130 2007-10-23 12:14:36Z doublecompile $
20
 */
21
/**
22
 * @see Xyster_Orm_Mapper_Abstract
23
 */
24 1
require_once 'Xyster/Orm/Mapper/Abstract.php';
25
/**
26
 * We might as well require this now... sets use it as well as the reportQuery
27
 * @see Xyster_Data_Set
28
 */
29 1
require_once 'Xyster/Data/Set.php';
30
/**
31
 * A SQL implementation of the mapper interface
32
 *
33
 * @see       Xyster_Orm_Mapper_Interface
34
 * @category  Xyster
35
 * @package   Xyster_Orm
36
 * @copyright Copyright (c) 2007 Irrational Logic (http://devweblog.org)
37
 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
38
 */
39
abstract class Xyster_Orm_Mapper extends Xyster_Orm_Mapper_Abstract
40
{
41
    /**
42
     * The data adapter
43
     *
44
     * @var Zend_Db_Adapter_Abstract
45
     */
46
    protected $_db;
47
48
    /**
49
     * Information provided by the getFields() method
50
     *
51
     * @var array
52
     * @see getFields()
53
     */
54
    protected $_metadata = array();
55
56
    /**
57
     * Cache for information provided the backend's getFields method
58
     *
59
     * @var Zend_Cache_Core
60
     */
61
    protected $_metadataCache;
62
63
    /**
64
     * Creates a new mapper
65
     *
66
     * @param Xyster_Orm_Mapper_Factory_Interface $factory
67
     * @param Zend_Cache_Core $cache
68
     */
69
    final public function __construct( Xyster_Orm_Mapper_Factory_Interface $factory, Zend_Cache_Core $cache = null )
70
    {
71 22
        if ( $cache ) {
72 22
            $this->_metadataCache = $cache;
73 22
        } else if ( array_key_exists('metadataCache', $this->_options) ) {
74 1
            $this->_metadataCache = self::_setupMetadataCache($this->_options['metadataCache']);
75 1
        }
76
77 22
        parent::__construct($factory);
78
    }
79
80
    /**
81
     * Sets up a nickname for a database adapter
82
     *
83
     * This method adds a Zend_Db_Adapter_Abstract to the Zend_Registry so it
84
     * can be retrieved later.
85
     *
86
     * @param string $dsn
87
     * @param string $driver
88
     * @param array $config
89
     */
90
    static public function dsn( $dsn, $driver, array $config = array() )
91
    {
92 22
        require_once 'Zend/Registry.php';
93 22
        require_once 'Zend/Db.php';
94
95 22
        $adapter = ( $driver instanceof Zend_Db_Adapter_Abstract ) ?
96 22
            $driver : Zend_Db::factory($driver, $config);
97 22
        Zend_Registry::set(md5($dsn), $adapter);
98
    }
99
100
    /**
101
     * Gets the first entity from the data store matching the criteria
102
     *
103
     * @param mixed $criteria
104
     * @return Xyster_Orm_Entity  The entity found
105
     */
106
    final public function find( $criteria )
107
    {
108 11
        $_criteria = $this->_buildCriteria($criteria);
109 11
		return $this->_mapEntity($this->_fetchOne($_criteria));
110
    }
111
112
    /**
113
     * Gets all entities from the data store matching the criteria
114
     *
115
     * @param mixed $criteria
116
     * @param mixed $sort
117
     * @return Xyster_Orm_Set  A collection of the entities
118
     */
119
    final public function findAll( $criteria, $sort = null )
120
    {
121 3
	    $select = $this->_buildSimpleSelect();
122 3
        $translator = $this->_buildTranslator();
123
124 3
        $token = $translator->translate($this->_buildCriteria($criteria));
125 3
		$select->where($token->getSql());
126 3
		$binds = $token->getBindValues();
127
128 3
	    if ( $sort !== null ) {
129 1
	        if ( !is_array($sort) ) {
130 1
	            $sort = array($sort);
131 1
	        }
132 1
		    foreach( $sort as $s ) {
133 1
		        if (! $s instanceof Xyster_Data_Sort ) {
134 1
		            require_once 'Xyster/Orm/Mapper/Exception.php';
135 1
                    throw new Xyster_Orm_Mapper_Exception("The sort parameter must be a single Xyster_Data_Sort or an array with multiple");
136 0
		        } else {
137 1
		            $token = $translator->translateSort($s, false);
138 1
		            $select->order($token->getSql());
139
		        }
140 1
		    }
141 1
	    }
142
143 3
	    return $this->_mapSet($this->_getAdapter()->query($select, $binds));
144
    }
145
146
    /**
147
     * Gets all entities from the data store
148
     *
149
     * @param array $ids  An array of ids for which entities to retrieve
150
     * @return Xyster_Orm_Set  A collection of the entities
151
     */
152
    final public function getAll( array $ids = array() )
153
    {
154 6
	    $orWhere = array();
155 6
        foreach( $ids as $id ) {
156 4
    	    $id = $this->_checkPrimaryKey($id);
157 4
            $orWhere[] = $this->_buildCriteria($id);
158 4
        }
159
160 6
	    $select = $this->_buildSimpleSelect();
161 6
        $binds = array();
162
163 6
        if ( count($orWhere) ) {
164 4
            require_once 'Xyster/Data/Junction.php';
165 4
            $translator = $this->_buildTranslator();
166 4
            $where = Xyster_Data_Junction::fromArray('OR', $orWhere);
167 4
            $token = $translator->translate($where);
168 4
    		$select->where($token->getSql());
169 4
		    $binds += $token->getBindValues();
170 4
        }
171
172 6
	    return $this->_mapSet($this->_getAdapter()->query($select, $binds));
173
    }
174
175
    /**
176
	 * Gets the fields for an entity as they appear in the backend
177
	 *
178
	 * The array should come in the format of the describeTable method of the
179
	 * Zend_Db_Adapter_Abstract class.
180
	 *
181
	 * @see Zend_Db_Adapter_Abstract::describeTable
182
	 * @return array
183
	 */
184
    final public function getFields()
185
    {
186 22
        if ( !$this->_metadata ) {
187
188 22
            $cache = $this->getMetadataCache();
189
190
            // If $this has a metadata cache
191 22
	        if (null !== $cache) {
192
	            // Define the cache identifier where the metadata are saved
193 22
	            $cacheId = md5($this->getTable());
194 22
	        }
195
196
	        // If $this has no metadata cache or metadata cache misses
197 22
	        if (null === $cache || !($metadata = $cache->load($cacheId))) {
198
	            // Fetch metadata from the adapter's describeTable() method
199 22
	            $metadata = $this->_getAdapter()->describeTable($this->getTable());
200
	            // If $this has a metadata cache, then cache the metadata
201 22
	            if (null !== $cache && !$cache->save($metadata, $cacheId)) {
202 1
	                require_once 'Xyster/Orm/Mapper/Exception.php';
203 1
	                throw new Xyster_Orm_Mapper_Exception('Failed saving metadata to metadataCache');
204 0
	            }
205 22
	        }
206
207
	        // Assign the metadata to $this
208 22
	        $this->_metadata = $metadata;
209 22
        }
210 22
        return $this->_metadata;
211
    }
212
213
    /**
214
     * Gets entities via a many-to-many table
215
     *
216
     * @param Xyster_Orm_Entity $entity
217
     * @param Xyster_Orm_Relation $relation
218
     * @return Xyster_Orm_Set
219
     */
220
    public function getJoined( Xyster_Orm_Entity $entity, Xyster_Orm_Relation $relation )
221
    {
222 4
        $db = $this->_getAdapter();
223 4
        $rightMap = $this->_factory->get($relation->getTo());
224
225 4
        $targetTable = $rightMap->getTable();
226 4
		$targetTableAlias = 't2';
227 4
        $columns = array();
228 4
		foreach( $rightMap->getFields() as $name => $v ) {
229 4
			$alias = $rightMap->translateField($name);
230 4
			$columns[$alias] = $targetTableAlias.'.'.$name;
231 4
		}
232
233
		// get the join SQL for the left to the middle
234 4
		$firstCond = array();
235 4
		$left = $relation->getLeft();
236 4
		foreach( $this->getEntityMeta()->getPrimary() as $k=>$primary ) {
237 4
		    $firstCond[] = $db->quoteIdentifier('t1') . '.'
238 4
		        . $db->quoteIdentifier($this->untranslateField($primary))
239 4
		        . ' = ' . $db->quoteIdentifier($relation->getTable()) . '.'
240 4
		        . $db->quoteIdentifier($left[$k]);
241 4
		}
242 4
		$firstCond = implode(' AND ', $firstCond);
243
244
		// get the join SQL for the middle to the right
245 4
		$secondCond = array();
246 4
		$right = $relation->getRight();
247 4
		foreach( $rightMap->getEntityMeta()->getPrimary() as $k=>$primary ) {
248 4
		    $secondCond[] = $db->quoteIdentifier($relation->getTable()) . '.'
249 4
		        . $db->quoteIdentifier($right[$k]) . ' = '
250 4
		        . $db->quoteIdentifier($targetTableAlias) . '.'
251 4
		        . $db->quoteIdentifier($rightMap->untranslateField($primary));
252 4
		}
253 4
		$secondCond = implode(' AND ', $secondCond);
254
255 4
		$select = $this->_getAdapter()->select();
256
257 4
		$translator = $this->_buildTranslator();
258 4
		$translator->setTable('t1');
259 4
		$token = $translator->translate($entity->getPrimaryKeyAsCriterion());
260
261 4
		$binds = $token->getBindValues();
262 4
		$select->from(array('t1'=>$this->getTable()), array())
263 4
		    ->join($relation->getTable(), $firstCond, array())
264 4
		    ->join(array($targetTableAlias=>$targetTable), $secondCond, $columns)
265 4
		    ->where($token->getSql());
266
267 4
		return $rightMap->_mapSet($this->_getAdapter()->query($select, $binds));
268
    }
269
270
    /**
271
     * Gets the metadata cache
272
     *
273
     * @return Zend_Cache_Core
274
     */
275
    final public function getMetadataCache()
276
    {
277 22
        return $this->_metadataCache;
278
    }
279
280
    /**
281
     * Gets the sequence of this table
282
     *
283
     * @return string The sequence
284
     */
285
    final public function getSequence()
286
    {
287 3
        return $this->getOption('sequence');
288
    }
289
290
    /**
291
	 * Performs a query
292
	 *
293
	 * @param Xyster_Orm_Query $query  The query details
294
	 * @return Xyster_Data_Set
295
	 */
296
	public function query( Xyster_Orm_Query $query )
297
	{
298 4
	    $db = $this->_getAdapter();
299
300 4
        require_once 'Xyster/Orm/Mapper/Translator.php';
301 4
		$translator = new Xyster_Orm_Mapper_Translator($db,
302 4
		    $this->getEntityName(), $this->_factory);
303
304 4
		$select = $db->select();
305 4
		$binds = array();
306
307
		// apply the where clause that can be run on the database
308 4
		foreach( $query->getBackendWhere() as $criterion ) {
309 4
			$whereToken = $translator->translateCriterion($criterion);
310 4
			$select->where( $whereToken->getSql() );
311 4
			$binds += $whereToken->getBindValues();
312 4
		}
313
314
		// apply the order by clause that can be run on the database
315 4
		if ( !$query->hasRuntimeOrder() ) {
316 4
			foreach( $query->getOrder() as $sort ) {
317 2
				$select->order($translator->translateSort($sort, false)->getSql());
318 2
			}
319 4
		}
320
321
		// if the query is entirely against the database, add limit & offset
322 4
		if ( !$query->isRuntime() && $query->getLimit() ) {
323 2
		    $select->limit($query->getLimit(), $query->getOffset());
324 2
		}
325
326 4
		if (! $query instanceof Xyster_Orm_Query_Report ) {
327
328
		    // add the from clause, joins, and columns
329 1
			$select->from(array($translator->getMain() => $this->getTable()), $this->_selectColumns());
330 1
			foreach( $translator->getFromClause() as $table => $joinToken ) {
331 1
			    $select->joinLeft($table, $joinToken->getSql(), array());
332 1
			    $binds += $joinToken->getBindValues();
333 1
			}
334
335 1
			return $this->_mapSet($db->query($select, $binds));
336
337 0
		} else {
338
339
		    // pretty self explanitory...
340 3
            $select->distinct($query->isDistinct());
341
342 3
	        $fields = array();
343 3
			if ( !$query->isRuntime() ) {
344
345 2
				foreach( $query->getFields() as $k=>$field ) {
346
				    // we want to quote the field names for aggregates!
347
	                // Zend_Db_Select does not do this for functions
348 2
				    $quote = ($field instanceof Xyster_Data_Field_Aggregate);
349 2
				    $fieldName = $translator->translateField($field, $quote)->getSql();
350 2
				    if ( $field->getAlias() == $field->getName() ) {
351 1
				        $fields[] = $fieldName;
352 1
				    } else {
353 2
				        $fields[$field->getAlias()] = $fieldName;
354
				    }
355 2
				}
356
357 2
				if ( count($query->getGroup()) ) {
358
				    // add the group clause
359 1
					foreach( $query->getGroup() as $k=>$grp ) {
360 1
						$fieldName = $translator->translateField($grp, false)->getSql();
361 1
						if ( $grp->getAlias() == $grp->getName() ) {
362 1
						    $fields[] = $fieldName;
363 1
						} else {
364 1
						    $fields[$grp->getAlias()] = $fieldName;
365
						}
366 1
						$select->group($fieldName);
367 1
					}
368
					// add the having clause
369 1
					foreach( $query->getHaving() as $k=>$crit ) {
370 1
						$whereToken = $translator->translateCriterion($crit);
371 1
						$select->having($whereToken->getSql());
372 1
						$binds += $whereToken->getBindValues();
373 1
					}
374 1
				}
375
376 2
			} else {
377
			    // it's runtime, just pull back all fields in the main table
378 1
			    $fields = $this->_selectColumns();
379
			}
380
381
			// add the from clause, joins, and columns
382 3
		    $select->from(array($translator->getMain() => $this->getTable()), $fields);
383 3
			foreach( $translator->getFromClause() as $table => $joinToken ) {
384 1
			    $select->joinLeft($table, $joinToken->getSql(), array());
385 1
			    $binds += $joinToken->getBindValues();
386 1
			}
387
388 3
			if ( !$query->isRuntime() ) {
389 2
			    $result = $db->query($select, $binds)->fetchAll(Zend_Db::FETCH_ASSOC);
390 2
				return new Xyster_Data_Set(Xyster_Collection::using($result));
391 0
			} else {
392 1
			    return $this->_mapSet($db->query($select, $binds));
393
			}
394
		}
395
	}
396
397
    /**
398
	 * Reloads an entity's values with fresh ones from the backend
399
	 *
400
	 * @param Xyster_Orm_Entity $entity  The entity to refresh
401
	 */
402
	public function refresh( Xyster_Orm_Entity $entity )
403
	{
404 9
	    $this->_mapEntity($this->_fetchOne($entity->getPrimaryKeyAsCriterion()), $entity);
405
	}
406
407
    /**
408
     * Gets a simple Select object for this table
409
     *
410
     * @return Zend_Db_Select
411
     */
412
    protected function _buildSimpleSelect()
413
    {
414 15
        $select = $this->_getAdapter()->select();
415 15
		$select->from(array('t1' => $this->getTable()), $this->_selectColumns());
416
417 15
		return $select;
418
    }
419
420
    /**
421
     * Gets a Mapper Translator object
422
     *
423
     * @return Xyster_Db_Translator
424
     */
425
    protected function _buildTranslator()
426
    {
427 14
        require_once 'Xyster/Db/Translator.php';
428 14
		$translator = new Xyster_Db_Translator($this->_getAdapter());
429 14
		$translator->setRenameCallback(array($this, 'untranslateField'));
430 14
		return $translator;
431
    }
432
433
	/**
434
	 * Removes entities from the backend
435
	 *
436
	 * @param Xyster_Data_Criterion $where The criteria on which to remove entities
437
	 */
438
	protected function _delete( Xyster_Data_Criterion $where )
439
	{
440 2
	    $translator = $this->_buildTranslator();
441 2
		$token = $translator->translateCriterion($where);
442
443 2
		$stmt = $this->_getAdapter()->prepare('DELETE FROM '
444 2
			. $this->_getAdapter()->quoteIdentifier($this->getTable())
445 2
		    . ' WHERE ' . $token->getSql());
446 2
		$stmt->execute($token->getBindValues());
447
	}
448
449
	/**
450
	 * Fetches one record
451
	 *
452
	 * @param Xyster_Data_Criterion $where
453
	 * @return Zend_Db_Statement_Interface
454
	 */
455
	protected function _fetchOne( Xyster_Data_Criterion $where )
456
	{
457 12
	    $select = $this->_buildSimpleSelect();
458 12
		$select->limit(1);
459
460 12
		$translator = $this->_buildTranslator();
461 12
	    $token = $translator->translate($where);
462 12
		$select->where($token->getSql());
463
464 12
		return $this->_getAdapter()->query($select, $token->getBindValues());
465
	}
466
467
	/**
468
	 * Gets a connection to the database
469
	 *
470
	 * @return Zend_Db_Adapter_Abstract A connection to the database
471
	 * @throws Xyster_Orm_Mapper_Exception
472
	 */
473
	final protected function _getAdapter()
474
	{
475 22
	    if (! $this->_db instanceof Zend_Db_Adapter_Abstract ) {
476 22
            $key = md5($this->getDomain());
477 22
            require_once 'Zend/Registry.php';
478 22
            $db = Zend_Registry::isRegistered($key) ? Zend_Registry::get($key) : null;
479
480 22
            if (!$db instanceof Zend_Db_Adapter_Abstract) {
481 1
                require_once 'Xyster/Orm/Mapper/Exception.php';
482 1
                throw new Xyster_Orm_Mapper_Exception('A database connection has not been defined.  Please call the static "dsn" method to do so.');
483 0
            }
484 22
            $this->_db = $db;
485 22
	    }
486
487 22
        return $this->_db;
488
    }
489
490
    /**
491
	 * Saves a new entity into the backend
492
	 *
493
	 * @param Xyster_Orm_Entity $entity  The entity to insert
494
	 * @return mixed  The new primary key
495
	 */
496
	protected function _insert( Xyster_Orm_Entity $entity )
497
	{
498 3
	    $db = $this->_getAdapter();
499
500 3
	    $data = array();
501 3
	    foreach( $entity->toArray() as $name => $value ) {
502 3
	        $data[ $this->untranslateField($name) ] = $value;
503 3
	    }
504
505
        /**
506
         * This class assumes that if you have a compound primary key
507
         * and one of the columns in the key uses a sequence,
508
         * it's the _first_ column in the compound key.
509
         */
510 3
        $primary = array_map(array($this, 'untranslateField'),
511 3
            $this->getEntityMeta()->getPrimary());
512 3
        $pkIdentity = $primary[0];
513 3
        if ( count($primary) > 0 ) {
514 3
	        $fields = $this->getEntityMeta()->getFields();
515 3
	        foreach( $fields as $field ) {
516
	            /* @var $field Xyster_Orm_Entity_Field */
517 3
	            if ( $field->isIdentity() ) {
518 3
	                $posn = $field->getPrimaryPosition() - 1;
519 3
	                $pkIdentity = $primary[ $posn ];
520 3
	            }
521 3
	        }
522 3
        }
523
524 3
        $sequence = $this->getSequence();
525 3
        if ( !$sequence && $db instanceof Zend_Db_Adapter_Pdo_Pgsql ) {
526 0
            $sequence = $this->getTable() . "_" . $pkIdentity . "_seq";
527 0
        }
528
529
        /**
530
         * If this table uses a database sequence object and the data does not
531
         * specify a value, then get the next ID from the sequence and add it
532
         * to the row.  We assume that only the first column in a compound
533
         * primary key takes a value from a sequence.
534
         */
535 3
        if ( $sequence && !$data[$pkIdentity]) {
536 0
            $data[$pkIdentity] = $db->nextSequenceId($sequence);
537 0
        }
538
539
	    /**
540
         * If the primary key can be generated automatically, and no value was
541
         * specified in the user-supplied data, then omit it from the tuple
542
         */
543 3
        if ( array_key_exists($pkIdentity, $data) && $data[$pkIdentity] === null ) {
544 2
            unset($data[$pkIdentity]);
545 2
        }
546
547 3
        $db->insert($this->getTable(), $data);
548
549 3
        $primaryKey = null;
550 3
        if ( isset($data[$pkIdentity]) ) {
551
            /**
552
             * Return the primary key value or array of values if the
553
             * primary key is compound.  This handles:
554
             * - natural keys
555
             * - sequence-driven keys
556
             * - auto-increment keys when the user specifies a value
557
             */
558 2
            $pkData = array_intersect_key($data, array_flip($primary));
559 2
            if (count($primary) == 1) {
560 1
                $primaryKey = current($pkData);
561 1
            } else {
562 1
                $primaryKey = $pkData;
563
            }
564 2
        }
565
566 3
        if (!$sequence) {
567
            /**
568
             * Return the most recent ID generated by an auto-increment column
569
             */
570 3
            $primaryKey = $db->lastInsertId();
571 3
        }
572
573
        /**
574
         * Normalize the result to an array indexed by primary key column(s).
575
         */
576 3
        $newPrimaryKey = is_array($primaryKey) ?
577 3
            $primaryKey : array(current($primary) => $primaryKey);
578
579 3
        foreach( $newPrimaryKey as $name => $value ) {
580 3
            $field = $this->translateField($name);
581 3
            $entity->$field = $value;
582 3
        }
583
584 3
    	return $newPrimaryKey;
585
	}
586
587
    /**
588
     * Adds the entities to the many-to-many join
589
     *
590
     * @param Xyster_Orm_Set $set
591
     */
592
    protected function _joinedInsert( Xyster_Orm_Set $set )
593
    {
594 3
        $entity = $set->getRelatedEntity();
595 3
        $relation = $set->getRelation();
596
597 3
        $leftValues = array();
598 3
        $left = $relation->getLeft();
599 3
        foreach( $this->getEntityMeta()->getPrimary() as $k=>$primary ) {
600 3
            $leftValues[$left[$k]] = $entity->$primary;
601 3
        }
602
603 3
        $rightMap = $this->getFactory()->get($relation->getTo());
604 3
        $right = $relation->getRight();
605 3
        $rightPrimary = $rightMap->getEntityMeta()->getPrimary();
606
607 3
        foreach( $set->getDiffAdded() as $added ) {
608
            /* @var $added Xyster_Orm_Entity */
609 3
            if ( !$added->getBase() ) {
610 1
                $rightMap->save($added);
611 1
            }
612 3
            $values = $leftValues;
613 3
            foreach( $rightPrimary as $k=>$primary ) {
614 3
                $values[$right[$k]] = $added->$primary;
615 3
            }
616 3
            $this->_getAdapter()->insert($relation->getTable(), $values);
617 3
        }
618
    }
619
620
    /**
621
     * Removes the entities from the many-to-many join
622
     *
623
     * @param Xyster_Orm_Set $set
624
     */
625
    protected function _joinedDelete( Xyster_Orm_Set $set )
626
    {
627 3
        $entity = $set->getRelatedEntity();
628 3
        $relation = $set->getRelation();
629
630 3
		$firstCond = array();
631 3
		$left = $relation->getLeft();
632 3
		foreach( $this->getEntityMeta()->getPrimary() as $k=>$primary ) {
633 3
		    $firstCond[] = Xyster_Data_Expression::eq($left[$k], $entity->$primary);
634 3
		}
635 3
		$leftCriteria = Xyster_Data_Criterion::fromArray('AND', $firstCond);
636
637 3
        $rightMap = $this->getFactory()->get($relation->getTo());
638 3
		$right = $relation->getRight();
639 3
		$rightPrimary = $rightMap->getEntityMeta()->getPrimary();
640
641 3
		$diffRemoved = $set->getDiffRemoved();
642 3
		if ( !count($diffRemoved) ) {
643 2
		    return;
644 0
		}
645 1
		$secondCriteria = array();
646 1
		foreach( $diffRemoved as $removed ) {
647 1
		    $secondCond = array();
648 1
		    foreach( $rightPrimary as $k=>$primary ) {
649 1
    		    $secondCond[] = Xyster_Data_Expression::eq($right[$k], $removed->$primary);
650 1
    		}
651 1
    		$secondCriteria[] = Xyster_Data_Criterion::fromArray('AND', $secondCond);
652 1
		}
653 1
		$allSecondCriteria = Xyster_Data_Criterion::fromArray('OR', $secondCriteria);
654
655 1
		$where = Xyster_Data_Junction::all($leftCriteria, $allSecondCriteria);
656 1
		$translator = new Xyster_Db_Translator($this->_getAdapter());
657 1
		$token = $translator->translate($where);
658
659 1
		$stmt = $this->_getAdapter()->prepare('DELETE FROM '
660 1
		    . $this->_getAdapter()->quoteIdentifier($relation->getTable())
661 1
		    . ' WHERE ' . $token->getSql());
662
663 1
		$stmt->execute($token->getBindValues());
664
    }
665
666
	/**
667
	 * Translates the first row of a database recordset into an entity
668
	 *
669
	 * @param Zend_Db_Statement_Interface $stmt A statement containing the row to translate
670
	 * @param Xyster_Orm_Entity $entity  Optional.  An entity to refresh
671
	 * @return Xyster_Orm_Entity  The translated entity
672
	 */
673
	protected function _mapEntity( Zend_Db_Statement_Interface $stmt, Xyster_Orm_Entity $entity = null )
674
	{
675 12
	    $return = null;
676
677 12
		if ( $row = $stmt->fetch(Zend_Db::FETCH_ASSOC) ) {
678 11
			$this->_checkPropertyNames($row);
679 11
			$stmt->closeCursor();
680 11
			if ( $entity instanceof Xyster_Orm_Entity ) {
681 8
			    $return = $entity->import($row);
682 8
			} else {
683 11
			    $return = $this->_create($row);
684
			}
685 11
		}
686
687 12
		return $return;
688
	}
689
690
    /**
691
	 * Translates a database recordset into an entity set
692
	 *
693
	 * @param Zend_Db_Statement_Interface $stmt A statement containing rows to translate
694
	 * @return Xyster_Orm_Set  The translated set
695
	 */
696
	protected function _mapSet( Zend_Db_Statement_Interface $stmt )
697
	{
698 10
		$entities = array();
699 10
		$stmt->setFetchMode(Zend_Db::FETCH_ASSOC);
700 10
		foreach( $stmt->fetchAll() as $k => $row ) {
701 10
			if ( $k<1 ) {
702 10
				$this->_checkPropertyNames($row);
703 10
			}
704 10
			$entities[] = $this->_create($row);
705 10
		}
706 10
		$stmt->closeCursor();
707
708 10
		return $this->getSet(Xyster_Collection::using($entities));
709
	}
710
711
	/**
712
	 * Gets the columns to select
713
	 *
714
	 * @return array
715
	 */
716
	protected function _selectColumns()
717
	{
718 16
	    $columns = array();
719 16
		foreach( $this->getFields() as $name => $v ) {
720 16
			$alias = $this->translateField($name);
721 16
			$columns[$alias] = $name;
722 16
		}
723 16
		return $columns;
724
	}
725
726
    /**
727
     * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key
728
     * @return Zend_Cache_Core
729
     * @throws Xyster_Orm_Mapper_Exception
730
     */
731
    protected final function _setupMetadataCache($metadataCache)
732
    {
733 1
        if (is_string($metadataCache)) {
734 1
            require_once 'Zend/Registry.php';
735 1
            $metadataCache = Zend_Registry::get($metadataCache);
736 1
        }
737
738 1
        if ($metadataCache === null || $metadataCache instanceof Zend_Cache_Core) {
739 1
            return $metadataCache;
740 0
        }
741
742 1
        require_once 'Xyster/Orm/Mapper/Exception.php';
743 1
        throw new Xyster_Orm_Mapper_Exception('Argument must be of type Zend_Cache_Core, or a Registry key where a Zend_Cache_Core object is stored');
744
    }
745
746
	/**
747
	 * Updates the values of an entity in the backend
748
	 *
749
	 * @param Xyster_Orm_Entity $entity  The entity to update
750
	 */
751
	protected function _update( Xyster_Orm_Entity $entity )
752
	{
753 6
	    $db = $this->_getAdapter();
754
755 6
    	$values = array();
756 6
    	foreach( $entity->getDirtyFields() as $name => $value ) {
757 3
    	    $values[ $this->untranslateField($name) ] = $value;
758 3
    	}
759
760 6
	    $keyNames = $this->getEntityMeta()->getPrimary();
761 6
	    $key = $entity->getPrimaryKey(true);
762
763 6
	    $where = array();
764 6
	    foreach( $keyNames as $name ) {
765 6
	        $sql = $db->quoteIdentifier($this->untranslateField($name)) . ' = ?';
766 6
	        $where[] = $db->quoteInto($sql, $key[$name]);
767 6
    	}
768
769 6
    	if ( count($values) > 0 ) {
770 3
    	    $this->_getAdapter()->update($this->getTable(), $values, $where);
771 3
    	}
772
	}
773
}


Report generated at 2007-11-05T09:09:01-05:00