~fusonic/chive/1.1

« back to all changes in this revision

Viewing changes to yii/db/ar/CActiveFinder.php

  • Committer: Matthias Burtscher
  • Date: 2010-02-12 09:12:35 UTC
  • Revision ID: matthias.burtscher@fusonic.net-20100212091235-jqxrb62klx872ajc
* Updated Yii to 1.1.0
* Removed CodePress and CodeMirror
* Updated jQuery and some plugins
* Cleaned some code ...

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
 *
5
5
 * @author Qiang Xue <qiang.xue@gmail.com>
6
6
 * @link http://www.yiiframework.com/
7
 
 * @copyright Copyright &copy; 2008-2009 Yii Software LLC
 
7
 * @copyright Copyright &copy; 2008-2010 Yii Software LLC
8
8
 * @license http://www.yiiframework.com/license/
9
9
 */
10
10
 
15
15
 * {@link CActiveRecord}.
16
16
 *
17
17
 * @author Qiang Xue <qiang.xue@gmail.com>
18
 
 * @version $Id: CActiveFinder.php 1296 2009-08-06 21:44:44Z qiang.xue $
 
18
 * @version $Id: CActiveFinder.php 1683 2010-01-08 05:08:29Z qiang.xue $
19
19
 * @package system.db.ar
20
20
 * @since 1.0
21
21
 */
32
32
         * This property is internally used.
33
33
         * @since 1.0.2
34
34
         */
35
 
        public $baseLimited;
 
35
        public $baseLimited=false;
36
36
 
37
37
        private $_joinCount=0;
38
38
        private $_joinTree;
39
39
        private $_builder;
40
 
        private $_criteria;  // the criteria generated via named scope
41
40
 
42
41
        /**
43
42
         * Constructor.
44
43
         * A join tree is built up based on the declared relationships between active record classes.
45
44
         * @param CActiveRecord the model that initiates the active finding process
46
45
         * @param mixed the relation names to be actively looked for
47
 
         * @param CDbCriteria the criteria associated with the named scopes (since version 1.0.5)
48
46
         */
49
 
        public function __construct($model,$with,$criteria=null)
 
47
        public function __construct($model,$with)
50
48
        {
51
 
                $this->_criteria=$criteria;
52
49
                $this->_builder=$model->getCommandBuilder();
53
50
                $this->_joinTree=new CJoinElement($this,$model);
54
51
                $this->buildJoinTree($this->_joinTree,$with);
56
53
 
57
54
        /**
58
55
         * Uses the most aggressive join approach.
59
 
         * By default, several join statements may be generated in order to avoid
60
 
         * fetching duplicated data. By calling this method, all tables will be joined
61
 
         * together all at once.
62
 
         * @param boolean whether we should enforce join even when a limit option is placed on the primary table query.
63
 
         * Defaults to true. If false, we would still use two queries when there is a HAS_MANY/MANY_MANY relation and
64
 
         * the primary table has a LIMIT option. This parameter is available since version 1.0.3.
 
56
         * By calling this method, even if there is LIMIT/OFFSET option set for
 
57
         * the primary table query, we will still use a single SQL statement.
 
58
         * By default (without calling this method), the primary table will be queried
 
59
         * by itself so that LIMIT/OFFSET can be correctly applied.
65
60
         * @return CActiveFinder the finder object
66
61
         * @since 1.0.2
67
62
         */
68
 
        public function together($ignoreLimit=true)
 
63
        public function together()
69
64
        {
70
65
                $this->joinAll=true;
71
 
                if($ignoreLimit)
72
 
                        $this->baseLimited=false;
73
66
                return $this;
74
67
        }
75
68
 
76
69
        private function query($criteria,$all=false)
77
70
        {
78
 
                if($this->_criteria!==null)
79
 
                {
80
 
                        $this->_criteria->mergeWith($criteria);
81
 
                        $criteria=$this->_criteria;
82
 
                }
83
 
 
 
71
                $this->_joinTree->beforeFind();
 
72
                $this->_joinTree->model->applyScopes($criteria);
84
73
                $this->_joinTree->find($criteria);
85
74
                $this->_joinTree->afterFind();
86
75
 
118
107
        public function findByPk($pk,$condition='',$params=array())
119
108
        {
120
109
                Yii::trace(get_class($this->_joinTree->model).'.findByPk() eagerly','system.db.ar.CActiveRecord');
121
 
                $criteria=$this->_builder->createPkCriteria($this->_joinTree->model->getTableSchema(),$pk,$condition,$params);
 
110
                $criteria=$this->_builder->createPkCriteria($this->_joinTree->model->getTableSchema(),$pk,$condition,$params,$this->_joinTree->rawTableAlias.'.');
122
111
                return $this->query($criteria);
123
112
        }
124
113
 
128
117
        public function findAllByPk($pk,$condition='',$params=array())
129
118
        {
130
119
                Yii::trace(get_class($this->_joinTree->model).'.findAllByPk() eagerly','system.db.ar.CActiveRecord');
131
 
                $criteria=$this->_builder->createPkCriteria($this->_joinTree->model->getTableSchema(),$pk,$condition,$params);
 
120
                $criteria=$this->_builder->createPkCriteria($this->_joinTree->model->getTableSchema(),$pk,$condition,$params,$this->_joinTree->rawTableAlias.'.');
132
121
                return $this->query($criteria,true);
133
122
        }
134
123
 
138
127
        public function findByAttributes($attributes,$condition='',$params=array())
139
128
        {
140
129
                Yii::trace(get_class($this->_joinTree->model).'.findByAttributes() eagerly','system.db.ar.CActiveRecord');
141
 
                $criteria=$this->_builder->createColumnCriteria($this->_joinTree->model->getTableSchema(),$attributes,$condition,$params);
 
130
                $criteria=$this->_builder->createColumnCriteria($this->_joinTree->model->getTableSchema(),$attributes,$condition,$params,$this->_joinTree->rawTableAlias.'.');
142
131
                return $this->query($criteria);
143
132
        }
144
133
 
148
137
        public function findAllByAttributes($attributes,$condition='',$params=array())
149
138
        {
150
139
                Yii::trace(get_class($this->_joinTree->model).'.findAllByAttributes() eagerly','system.db.ar.CActiveRecord');
151
 
                $criteria=$this->_builder->createColumnCriteria($this->_joinTree->model->getTableSchema(),$attributes,$condition,$params);
 
140
                $criteria=$this->_builder->createColumnCriteria($this->_joinTree->model->getTableSchema(),$attributes,$condition,$params,$this->_joinTree->rawTableAlias.'.');
152
141
                return $this->query($criteria,true);
153
142
        }
154
143
 
161
150
                if(($row=$this->_builder->createSqlCommand($sql,$params)->queryRow())!==false)
162
151
                {
163
152
                        $baseRecord=$this->_joinTree->model->populateRecord($row,false);
 
153
                        $this->_joinTree->beforeFind();
164
154
                        $this->_joinTree->findWithBase($baseRecord);
165
155
                        $this->_joinTree->afterFind();
166
156
                        return $baseRecord;
176
166
                if(($rows=$this->_builder->createSqlCommand($sql,$params)->queryAll())!==array())
177
167
                {
178
168
                        $baseRecords=$this->_joinTree->model->populateRecords($rows,false);
 
169
                        $this->_joinTree->beforeFind();
179
170
                        $this->_joinTree->findWithBase($baseRecords);
180
171
                        $this->_joinTree->afterFind();
181
172
                        return $baseRecords;
192
183
        {
193
184
                Yii::trace(get_class($this->_joinTree->model).'.count() eagerly','system.db.ar.CActiveRecord');
194
185
                $criteria=$this->_builder->createCriteria($condition,$params);
195
 
                if($this->_criteria!==null)
196
 
                {
197
 
                        $this->_criteria->mergeWith($criteria);
198
 
                        $criteria=$this->_criteria;
199
 
                }
 
186
                $this->_joinTree->model->applyScopes($criteria);
200
187
                return $this->_joinTree->count($criteria);
201
188
        }
202
189
 
253
240
                        $model=CActiveRecord::model($relation->className);
254
241
                        if(($scope=$model->defaultScope())!==array())
255
242
                                $relation->mergeWith($scope);
256
 
                        if(isset($scopes) && !empty($scopes))
 
243
                        if(!empty($scopes))
257
244
                        {
258
245
                                $scs=$model->scopes();
259
246
                                foreach($scopes as $scope)
297
284
 * CJoinElement represents a tree node in the join tree created by {@link CActiveFinder}.
298
285
 *
299
286
 * @author Qiang Xue <qiang.xue@gmail.com>
300
 
 * @version $Id: CActiveFinder.php 1296 2009-08-06 21:44:44Z qiang.xue $
 
287
 * @version $Id: CActiveFinder.php 1683 2010-01-08 05:08:29Z qiang.xue $
301
288
 * @package system.db.ar
302
289
 * @since 1.0
303
290
 */
332
319
         * @var string table alias for this join element
333
320
         */
334
321
        public $tableAlias;
 
322
        /**
 
323
         * @var string the quoted table alias for this element
 
324
         */
 
325
        public $rawTableAlias;
335
326
 
336
327
        private $_finder;
337
328
        private $_builder;
345
336
        /**
346
337
         * Constructor.
347
338
         * @param CActiveFinder the finder
348
 
         * @param mixed the relation (if the second parameter is not null)
349
 
         * or the model (if the second parameter is null) associated with this tree node.
 
339
         * @param mixed the relation (if the third parameter is not null)
 
340
         * or the model (if the third parameter is null) associated with this tree node.
350
341
         * @param CJoinElement the parent tree node
351
342
         * @param integer the ID of this tree node that is unique among all the tree nodes
352
343
         */
359
350
                        $this->relation=$relation;
360
351
                        $this->_parent=$parent;
361
352
                        $this->_builder=$parent->_builder;
362
 
                        $this->tableAlias=$relation->alias===null?'t'.$id:$relation->alias;
 
353
                        $this->tableAlias=$relation->alias===null?$relation->name:$relation->alias;
 
354
                        $this->rawTableAlias=$this->_builder->getSchema()->quoteTableName($this->tableAlias);
363
355
                        $this->model=CActiveRecord::model($relation->className);
364
356
                        $this->_table=$this->model->getTableSchema();
365
357
                }
368
360
                        $this->model=$relation;
369
361
                        $this->_builder=$relation->getCommandBuilder();
370
362
                        $this->_table=$relation->getTableSchema();
 
363
                        $this->tableAlias='t';
 
364
                        $this->rawTableAlias=$this->_builder->getSchema()->quoteTableName('t');
371
365
                }
372
366
 
373
367
                // set up column aliases, such as t1_c2
396
390
                if($this->_parent===null) // root element
397
391
                {
398
392
                        $query=new CJoinQuery($this,$criteria);
399
 
                        if($this->_finder->baseLimited===null)
400
 
                                $this->_finder->baseLimited=($criteria->offset>=0 || $criteria->limit>=0);
 
393
                        $this->_finder->baseLimited=($criteria->offset>=0 || $criteria->limit>=0);
401
394
                        $this->buildQuery($query);
 
395
                        $this->_finder->baseLimited=false;
402
396
                        $this->runQuery($query);
403
397
                }
404
398
                else if(!$this->_joined && !empty($this->_parent->records)) // not joined before
440
434
                        return;
441
435
 
442
436
                $child=reset($this->children);
443
 
                $query=new CJoinQuery($this);
444
 
                $this->_joined=true;
445
 
                $child->_joined=true;
446
 
                $query->join($child);
 
437
                $query=new CJoinQuery($child);
 
438
                $query->selects=array();
 
439
                $query->selects[]=$child->getColumnSelect($child->relation->select);
 
440
                $query->conditions=array();
 
441
                $query->conditions[]=$child->relation->condition;
 
442
                $query->conditions[]=$child->relation->on;
 
443
                $query->groups[]=$child->relation->group;
 
444
                $query->havings[]=$child->relation->having;
 
445
                $query->orders[]=$child->relation->order;
 
446
                if(is_array($child->relation->params))
 
447
                        $query->params=$child->relation->params;
 
448
                $query->elements[$child->id]=true;
447
449
                if($child->relation instanceof CHasManyRelation)
448
450
                {
449
451
                        $query->limit=$child->relation->limit;
450
452
                        $query->offset=$child->relation->offset;
451
 
                        if($this->_finder->baseLimited===null)
452
 
                                $this->_finder->baseLimited=($query->offset>=0 || $query->limit>=0);
453
 
                        $query->groups[]=str_replace($child->relation->aliasToken.'.',$child->tableAlias.'.',$child->relation->group);
454
 
                        $query->havings[]=str_replace($child->relation->aliasToken.'.',$child->tableAlias.'.',$child->relation->having);
455
453
                }
 
454
 
 
455
                $child->applyLazyCondition($query,$baseRecord);
 
456
 
 
457
                $this->_joined=true;
 
458
                $child->_joined=true;
 
459
 
 
460
                $this->_finder->baseLimited=false;
456
461
                $child->buildQuery($query);
457
 
                $this->runQuery($query);
 
462
                $child->runQuery($query);
458
463
                foreach($child->children as $c)
459
464
                        $c->find();
 
465
 
 
466
                if(empty($child->records))
 
467
                        return;
 
468
                if($child->relation instanceof CHasOneRelation || $child->relation instanceof CBelongsToRelation)
 
469
                        $baseRecord->addRelatedRecord($child->relation->name,reset($child->records),false);
 
470
                else // has_many and many_many
 
471
                {
 
472
                        foreach($child->records as $record)
 
473
                        {
 
474
                                if($child->relation->index!==null)
 
475
                                        $index=$record->{$child->relation->index};
 
476
                                else
 
477
                                        $index=true;
 
478
                                $baseRecord->addRelatedRecord($child->relation->name,$record,$index);
 
479
                        }
 
480
                }
 
481
        }
 
482
 
 
483
        private function applyLazyCondition($query,$record)
 
484
        {
 
485
                $schema=$this->_builder->getSchema();
 
486
                $parent=$this->_parent;
 
487
                if($this->relation instanceof CManyManyRelation)
 
488
                {
 
489
                        if(!preg_match('/^\s*(.*?)\((.*)\)\s*$/',$this->relation->foreignKey,$matches))
 
490
                                throw new CDbException(Yii::t('yii','The relation "{relation}" in active record class "{class}" is specified with an invalid foreign key. The format of the foreign key must be "joinTable(fk1,fk2,...)".',
 
491
                                        array('{class}'=>get_class($parent->model),'{relation}'=>$this->relation->name)));
 
492
 
 
493
                        if(($joinTable=$schema->getTable($matches[1]))===null)
 
494
                                throw new CDbException(Yii::t('yii','The relation "{relation}" in active record class "{class}" is not specified correctly: the join table "{joinTable}" given in the foreign key cannot be found in the database.',
 
495
                                        array('{class}'=>get_class($parent->model), '{relation}'=>$this->relation->name, '{joinTable}'=>$matches[1])));
 
496
                        $fks=preg_split('/[\s,]+/',$matches[2],-1,PREG_SPLIT_NO_EMPTY);
 
497
 
 
498
 
 
499
                        $joinAlias=$schema->quoteTableName($this->relation->name.'_'.$this->tableAlias);
 
500
                        $parentCondition=array();
 
501
                        $childCondition=array();
 
502
                        $count=0;
 
503
                        $params=array();
 
504
                        foreach($fks as $i=>$fk)
 
505
                        {
 
506
                                if(isset($joinTable->foreignKeys[$fk]))  // FK defined
 
507
                                {
 
508
                                        list($tableName,$pk)=$joinTable->foreignKeys[$fk];
 
509
                                        if(!isset($parentCondition[$pk]) && $schema->compareTableNames($parent->_table->rawName,$tableName))
 
510
                                        {
 
511
                                                $parentCondition[$pk]=$joinAlias.'.'.$schema->quoteColumnName($fk).'=:ypl'.$count;
 
512
                                                $params[':ypl'.$count]=$record->$pk;
 
513
                                                $count++;
 
514
                                        }
 
515
                                        else if(!isset($childCondition[$pk]) && $schema->compareTableNames($this->_table->rawName,$tableName))
 
516
                                                $childCondition[$pk]=$this->getColumnPrefix().$schema->quoteColumnName($pk).'='.$joinAlias.'.'.$schema->quoteColumnName($fk);
 
517
                                        else
 
518
                                                throw new CDbException(Yii::t('yii','The relation "{relation}" in active record class "{class}" is specified with an invalid foreign key "{key}". The foreign key does not point to either joining table.',
 
519
                                                        array('{class}'=>get_class($parent->model), '{relation}'=>$this->relation->name, '{key}'=>$fk)));
 
520
                                }
 
521
                                else // FK constraints not defined
 
522
                                {
 
523
                                        if($i<count($parent->_table->primaryKey))
 
524
                                        {
 
525
                                                $pk=is_array($parent->_table->primaryKey) ? $parent->_table->primaryKey[$i] : $parent->_table->primaryKey;
 
526
                                                $parentCondition[$pk]=$joinAlias.'.'.$schema->quoteColumnName($fk).'=:ypl'.$count;
 
527
                                                $params[':ypl'.$count]=$record->$pk;
 
528
                                                $count++;
 
529
                                        }
 
530
                                        else
 
531
                                        {
 
532
                                                $j=$i-count($parent->_table->primaryKey);
 
533
                                                $pk=is_array($this->_table->primaryKey) ? $this->_table->primaryKey[$j] : $this->_table->primaryKey;
 
534
                                                $childCondition[$pk]=$this->getColumnPrefix().$schema->quoteColumnName($pk).'='.$joinAlias.'.'.$schema->quoteColumnName($fk);
 
535
                                        }
 
536
                                }
 
537
                        }
 
538
                        if($parentCondition!==array() && $childCondition!==array())
 
539
                        {
 
540
                                $join='INNER JOIN '.$joinTable->rawName.' '.$joinAlias.' ON ';
 
541
                                $join.='('.implode(') AND (',$parentCondition).') AND ('.implode(') AND (',$childCondition).')';
 
542
                                if(!empty($this->relation->on))
 
543
                                        $join.=' AND ('.$this->relation->on.')';
 
544
                                $query->joins[]=$join;
 
545
                                foreach($params as $name=>$value)
 
546
                                        $query->params[$name]=$value;
 
547
                        }
 
548
                        else
 
549
                                throw new CDbException(Yii::t('yii','The relation "{relation}" in active record class "{class}" is specified with an incomplete foreign key. The foreign key must consist of columns referencing both joining tables.',
 
550
                                        array('{class}'=>get_class($parent->model), '{relation}'=>$this->relation->name)));
 
551
                }
 
552
                else
 
553
                {
 
554
                        $fks=preg_split('/[\s,]+/',$this->relation->foreignKey,-1,PREG_SPLIT_NO_EMPTY);
 
555
                        $params=array();
 
556
                        foreach($fks as $i=>$fk)
 
557
                        {
 
558
                                if($this->relation instanceof CBelongsToRelation)
 
559
                                {
 
560
                                        if(isset($parent->_table->foreignKeys[$fk]))  // FK defined
 
561
                                                $pk=$parent->_table->foreignKeys[$fk][1];
 
562
                                        else if(is_array($this->_table->primaryKey)) // composite PK
 
563
                                                $pk=$this->_table->primaryKey[$i];
 
564
                                        else
 
565
                                                $pk=$this->_table->primaryKey;
 
566
                                        $params[$pk]=$record->$fk;
 
567
                                }
 
568
                                else
 
569
                                {
 
570
                                        if(isset($this->_table->foreignKeys[$fk]))  // FK defined
 
571
                                                $pk=$this->_table->foreignKeys[$fk][1];
 
572
                                        else if(is_array($parent->_table->primaryKey)) // composite PK
 
573
                                                $pk=$parent->_table->primaryKey[$i];
 
574
                                        else
 
575
                                                $pk=$parent->_table->primaryKey;
 
576
                                        $params[$fk]=$record->$pk;
 
577
                                }
 
578
                        }
 
579
                        $prefix=$this->getColumnPrefix();
 
580
                        $count=0;
 
581
                        foreach($params as $name=>$value)
 
582
                        {
 
583
                                $query->conditions[]=$prefix.$schema->quoteColumnName($name).'=:ypl'.$count;
 
584
                                $query->params[':ypl'.$count]=$value;
 
585
                                $count++;
 
586
                        }
 
587
                }
460
588
        }
461
589
 
462
590
        /**
522
650
                        $query->selects=array("COUNT(*)");
523
651
 
524
652
                $query->orders=$query->groups=$query->havings=array();
 
653
                $query->limit=$query->offset=-1;
525
654
                $command=$query->createCommand($this->_builder);
526
655
                return $command->queryScalar();
527
656
        }
528
657
 
529
658
        /**
 
659
         * Calls {@link CActiveRecord::beforeFind}.
 
660
         * @since 1.0.11
 
661
         */
 
662
        public function beforeFind()
 
663
        {
 
664
                $this->model->beforeFindInternal();
 
665
        }
 
666
 
 
667
        /**
530
668
         * Calls {@link CActiveRecord::afterFind} of all the records.
531
669
         * @since 1.0.3
532
670
         */
547
685
                foreach($this->children as $child)
548
686
                {
549
687
                        if($child->relation instanceof CHasOneRelation || $child->relation instanceof CBelongsToRelation
550
 
                                || $child->relation->together || ($this->_finder->joinAll && !$this->_finder->baseLimited))
 
688
                                || $this->_finder->joinAll || !$this->_finder->baseLimited && $child->relation->together)
551
689
                        {
552
690
                                $child->_joined=true;
553
691
                                $query->join($child);
650
788
        public function getTableNameWithAlias()
651
789
        {
652
790
                if($this->tableAlias!==null)
653
 
                        return $this->_table->rawName . ' ' . $this->tableAlias;
 
791
                        return $this->_table->rawName . ' ' . $this->rawTableAlias;
654
792
                else
655
793
                        return $this->_table->rawName;
656
794
        }
714
852
                        }
715
853
                }
716
854
 
717
 
                $select=implode(', ',$columns);
718
 
                if($this->relation!==null)
719
 
                        return str_replace($this->relation->aliasToken.'.', $prefix, $select);
720
 
                else
721
 
                        return $select;
 
855
                return implode(', ',$columns);
722
856
        }
723
857
 
724
858
        /**
756
890
        }
757
891
 
758
892
        /**
759
 
         * @return string the WHERE clause. Column references are properly disambiguated.
760
 
         */
761
 
        public function getCondition()
762
 
        {
763
 
                if($this->relation->condition!=='' && $this->tableAlias!==null)
764
 
                        return str_replace($this->relation->aliasToken.'.', $this->tableAlias.'.', $this->relation->condition);
765
 
                else
766
 
                        return $this->relation->condition;
767
 
        }
768
 
 
769
 
        /**
770
 
         * @return string the ORDER BY clause. Column references are properly disambiguated.
771
 
         */
772
 
        public function getOrder()
773
 
        {
774
 
                if($this->relation->order!=='' && $this->tableAlias!==null)
775
 
                        return str_replace($this->relation->aliasToken.'.',$this->tableAlias.'.',$this->relation->order);
776
 
                else
777
 
                        return $this->relation->order;
778
 
        }
779
 
 
780
 
        /**
781
 
         * @return string the GROUP BY clause. Column references are properly disambiguated.
782
 
         * @since 1.0.4
783
 
         */
784
 
        public function getGroupBy()
785
 
        {
786
 
                if($this->relation->group!=='' && $this->tableAlias!==null)
787
 
                        return str_replace($this->relation->aliasToken.'.', $this->tableAlias.'.', $this->relation->group);
788
 
                else
789
 
                        return $this->relation->group;
790
 
        }
791
 
 
792
 
        /**
793
 
         * @return string the HAVING clause. Column references are properly disambiguated.
794
 
         * @since 1.0.4
795
 
         */
796
 
        public function getHaving()
797
 
        {
798
 
                if($this->relation->having!=='' && $this->tableAlias!==null)
799
 
                        return str_replace($this->relation->aliasToken.'.', $this->tableAlias.'.', $this->relation->having);
800
 
                else
801
 
                        return $this->relation->having;
802
 
        }
803
 
 
804
 
        /**
805
893
         * @return string the column prefix for column reference disambiguation
806
894
         */
807
895
        public function getColumnPrefix()
808
896
        {
809
897
                if($this->tableAlias!==null)
810
 
                        return $this->tableAlias.'.';
 
898
                        return $this->rawTableAlias.'.';
811
899
                else
812
900
                        return $this->_table->rawName.'.';
813
901
        }
882
970
                        $joins[]=$fke->getColumnPrefix().$schema->quoteColumnName($fk) . '=' . $pke->getColumnPrefix().$schema->quoteColumnName($pk);
883
971
                }
884
972
                if(!empty($this->relation->on))
885
 
                        $joins[]=str_replace($this->relation->aliasToken.'.', $this->tableAlias.'.', $this->relation->on);
 
973
                        $joins[]=$this->relation->on;
886
974
                return $this->relation->joinType . ' ' . $this->getTableNameWithAlias() . ' ON (' . implode(') AND (',$joins).')';
887
975
        }
888
976
 
897
985
        private function joinManyMany($joinTable,$fks,$parent)
898
986
        {
899
987
                $schema=$this->_builder->getSchema();
900
 
                $joinAlias=$this->relation->name.'_'.$this->tableAlias;
 
988
                $joinAlias=$schema->quoteTableName($this->relation->name.'_'.$this->tableAlias);
901
989
                $parentCondition=array();
902
990
                $childCondition=array();
903
991
                foreach($fks as $i=>$fk)
939
1027
                        $join.=' '.$this->relation->joinType.' '.$this->getTableNameWithAlias();
940
1028
                        $join.=' ON ('.implode(') AND (',$childCondition).')';
941
1029
                        if(!empty($this->relation->on))
942
 
                                $join.=' AND ('.str_replace($this->relation->aliasToken.'.', $this->tableAlias.'.', $this->relation->on).')';
 
1030
                                $join.=' AND ('.$this->relation->on.')';
943
1031
                        return $join;
944
1032
                }
945
1033
                else
953
1041
 * CJoinQuery represents a JOIN SQL statement.
954
1042
 *
955
1043
 * @author Qiang Xue <qiang.xue@gmail.com>
956
 
 * @version $Id: CActiveFinder.php 1296 2009-08-06 21:44:44Z qiang.xue $
 
1044
 * @version $Id: CActiveFinder.php 1683 2010-01-08 05:08:29Z qiang.xue $
957
1045
 * @package system.db.ar
958
1046
 * @since 1.0
959
1047
 */
964
1052
         */
965
1053
        public $selects=array();
966
1054
        /**
 
1055
         * @var boolean whether to select distinct result set
 
1056
         * @since 1.0.9
 
1057
         */
 
1058
        public $distinct=false;
 
1059
        /**
967
1060
         * @var array list of join statement
968
1061
         */
969
1062
        public $joins=array();
1019
1112
                        $this->limit=$criteria->limit;
1020
1113
                        $this->offset=$criteria->offset;
1021
1114
                        $this->params=$criteria->params;
 
1115
                        if(!$this->distinct && $criteria->distinct)
 
1116
                                $this->distinct=true;
1022
1117
                }
1023
1118
                else
1024
1119
                {
1036
1131
        public function join($element)
1037
1132
        {
1038
1133
                $this->selects[]=$element->getColumnSelect($element->relation->select);
1039
 
                $this->conditions[]=$element->getCondition();
1040
 
                $this->orders[]=$element->getOrder();
 
1134
                $this->conditions[]=$element->relation->condition;
 
1135
                $this->orders[]=$element->relation->order;
1041
1136
                $this->joins[]=$element->getJoinCondition();
1042
 
                $this->groups[]=$element->getGroupBy();
1043
 
                $this->havings[]=$element->getHaving();
 
1137
                $this->groups[]=$element->relation->group;
 
1138
                $this->havings[]=$element->relation->having;
1044
1139
 
1045
1140
                if(is_array($element->relation->params))
1046
1141
                {
1059
1154
         */
1060
1155
        public function createCommand($builder)
1061
1156
        {
1062
 
                $sql='SELECT ' . implode(', ',$this->selects);
 
1157
                $sql=($this->distinct ? 'SELECT DISTINCT ':'SELECT ') . implode(', ',$this->selects);
1063
1158
                $sql.=' FROM ' . implode(' ',$this->joins);
1064
1159
 
1065
1160
                $conditions=array();
1102
1197
 * CStatElement represents STAT join element for {@link CActiveFinder}.
1103
1198
 *
1104
1199
 * @author Qiang Xue <qiang.xue@gmail.com>
1105
 
 * @version $Id: CActiveFinder.php 1296 2009-08-06 21:44:44Z qiang.xue $
 
1200
 * @version $Id: CActiveFinder.php 1683 2010-01-08 05:08:29Z qiang.xue $
1106
1201
 * @package system.db.ar
1107
1202
 * @since 1.0.4
1108
1203
 */
1148
1243
                $builder=$model->getCommandBuilder();
1149
1244
                $schema=$builder->getSchema();
1150
1245
                $table=$model->getTableSchema();
1151
 
                $pkTable=$this->_parent->model->getTableSchema();
 
1246
                $parent=$this->_parent;
 
1247
                $pkTable=$parent->model->getTableSchema();
1152
1248
 
1153
1249
                $fks=preg_split('/[\s,]+/',$relation->foreignKey,-1,PREG_SPLIT_NO_EMPTY);
1154
1250
                if(count($fks)!==count($pkTable->primaryKey))
1174
1270
                        }
1175
1271
                        else  // FK constraints undefined
1176
1272
                        {
1177
 
                                if(is_array($table->primaryKey)) // composite PK
1178
 
                                        $map[$table->primaryKey[$i]]=$fk;
 
1273
                                if(is_array($pkTable->primaryKey)) // composite PK
 
1274
                                        $map[$pkTable->primaryKey[$i]]=$fk;
 
1275
                                else
 
1276
                                        $map[$pkTable->primaryKey]=$fk;
1179
1277
                        }
1180
1278
                }
1181
1279