http://phing.info/

Source Code Coverage

Designed for use with PHPUnit2, Xdebug and Phing.

Methods: 24 LOC: 762 Statements: 342

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


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