11<?php namespace SimpleAR \Database \Builder ;
22
33use \SimpleAR \Database \Builder ;
4- // use \SimpleAR\Database\Condition\Exists as ExistsCond;
5- // use \SimpleAR\Database\Condition\Nested as NestedCond;
6- // use \SimpleAR\Database\Condition\Simple as SimpleCond;
7- // use \SimpleAR\Database\Condition\Attribute as AttrCond;
8- // use \SimpleAR\Database\Condition\SubQuery as SubQueryCond;
94use \SimpleAR \Database \Expression ;
105use \SimpleAR \Database \JoinClause ;
116use \SimpleAR \Database \Query ;
12-
137use \SimpleAR \Exception \MalformedOptionException ;
148use \SimpleAR \Exception ;
15-
169use \SimpleAR \Facades \Cfg ;
1710use \SimpleAR \Facades \DB ;
18-
1911use \SimpleAR \Orm \Relation ;
12+ use \SimpleAR \Orm \Relation \ManyMany ;
2013use \SimpleAR \Orm \Table ;
2114
2215class WhereBuilder extends Builder
@@ -100,6 +93,13 @@ public function where($attribute, $op = null, $val = null, $logic = 'AND', $not
10093 return ;
10194 }
10295
96+ // User wants a WHERE NULL condition.
97+ if ($ val === null )
98+ {
99+ $ this ->whereNull ($ attribute , $ logic , $ op === '!= ' );
100+ return ;
101+ }
102+
103103 list ($ table , $ cols ) = $ this ->_processExtendedAttribute ($ attribute );
104104
105105 $ type = 'Basic ' ;
@@ -185,6 +185,32 @@ public function whereIn($attribute, $val, $logic = 'AND', $not = false)
185185 $ this ->_addWhere ($ cond , $ val );
186186 }
187187
188+ /**
189+ * Add a WHERE NULL clause to the query.
190+ *
191+ * @param string $attribute The extended attribute.
192+ * @param string $logic The logical operator.
193+ */
194+ public function whereNull ($ attribute , $ logic = 'AND ' , $ not = false )
195+ {
196+ list ($ table , $ cols ) = $ this ->_processExtendedAttribute ($ attribute );
197+
198+ $ type = 'Null ' ;
199+ $ cond = compact ('type ' , 'table ' , 'cols ' , 'logic ' , 'not ' );
200+ $ this ->_addWhere ($ cond );
201+ }
202+
203+ /**
204+ * Add a WHERE NOT NULL clause to the query.
205+ *
206+ * @param string $attribute The extended attribute.
207+ * @param string $logic The logical operator.
208+ */
209+ public function whereNotNull ($ attribute , $ logic )
210+ {
211+ $ this ->whereNull ($ attributes , $ logic , true );
212+ }
213+
188214 /**
189215 * Get the separation character of relation names in options.
190216 *
@@ -440,7 +466,7 @@ public function addInvolvedTable($tableAlias, $joinType = JoinClause::INNER)
440466 $ this ->setInvolvedModel ($ alias , $ currentModel );
441467 $ this ->setInvolvedTable ($ alias , $ currentTable );
442468 $ this ->_addJoinClause (
443- $ currentTable , $ alias ,
469+ $ currentTable-> name , $ alias ,
444470 $ currentRel , $ previousAlias ,
445471 $ joinType
446472 );
@@ -461,6 +487,12 @@ public function getNextRelationByModel($model, $relation)
461487 return $ model ::relation ($ relation );
462488 }
463489
490+ /**
491+ * Return the linked model class name of a relation.
492+ *
493+ * @param Relation $relation The relation
494+ * @return string The linked model class name.
495+ */
464496 public function getNextModelByRelation (Relation $ relation )
465497 {
466498 return $ relation ->lm ->class ;
@@ -477,36 +509,67 @@ public function getNextModelByRelation(Relation $relation)
477509 * @param Table
478510 * @param string
479511 */
480- protected function _addJoinClause (Table $ toJoin , $ toJoinAlias ,
481- Relation $ rel = null , $ previousAlias = '' ,
512+ protected function _addJoinClause ($ lmTable , $ lmAlias ,
513+ Relation $ rel = null , $ cmAlias = '' ,
482514 $ joinType = JoinClause::INNER
483515 ) {
484- $ jc = new JoinClause ($ toJoin ->name , $ toJoinAlias , $ joinType );
516+
517+ // If relation cardinality is many-to-many, we must join middle table.
518+ if ($ rel instanceof ManyMany)
519+ {
520+ // _addJoinClauseManyMany returns the alias of the middle table. We
521+ // are going to use it to join the middle table with the LM table.
522+ $ cmAlias = $ this ->_addJoinClauseManyMany ($ rel , $ cmAlias , $ joinType );
523+ }
524+
525+ $ jc = new JoinClause ($ lmTable , $ lmAlias , $ joinType );
485526
486527 // We may have to connect it to a previous JoinClause.
487528 if ($ rel )
488529 {
489530 // $rel->cm corresponds to previous model.
490531 foreach ($ rel ->getJoinColumns () as $ leftCol => $ rightCol )
491532 {
492- $ jc ->on ($ previousAlias , $ leftCol , $ toJoinAlias , $ rightCol );
533+ $ jc ->on ($ cmAlias , $ leftCol , $ lmAlias , $ rightCol );
493534 }
494535 }
495536
496- $ this ->_joinClauses [$ toJoinAlias ] = $ jc ;
537+ $ this ->_joinClauses [$ lmAlias ] = $ jc ;
538+ }
539+
540+ protected function _addJoinClauseManyMany (ManyMany $ rel , $ cmAlias , $ joinType )
541+ {
542+ // $md stands for "middle".
543+ $ mdTable = $ rel ->getMiddleTableName ();
544+ $ mdAlias = $ rel ->getMiddleTableAlias ();
545+ $ jcMiddle = new JoinClause ($ mdTable , $ mdAlias , $ joinType );
546+
547+ foreach ($ rel ->getMiddleJoinColumns () as $ lCol => $ rCol )
548+ {
549+ $ jcMiddle ->on ($ cmAlias , $ lCol , $ mdAlias , $ rCol );
550+ }
551+
552+ $ this ->_joinClauses [$ mdAlias ] = $ jcMiddle ;
553+
554+ return $ mdAlias ;
497555 }
498556
499557 /**
500558 * Add a condition to the list of conditions.
501559 *
502560 * @param array $cond The condition array
503- * @param mixed $val The condition's value. It will be add to query's
504- * values list.
561+ *
562+ * There is no second optional argument in order to allow function caller to
563+ * pass a null value.
505564 */
506- protected function _addWhere (array $ cond, $ val = null )
565+ protected function _addWhere (array $ cond )
507566 {
508567 $ this ->_components ['where ' ][] = $ cond ;
509- $ val && $ this ->addValueToQuery ($ val , 'where ' );
568+
569+ if (func_num_args () > 1 )
570+ {
571+ $ this ->addValueToQuery (func_get_arg (1 ), 'where ' );
572+ }
510573 }
511574
512575 /**
@@ -621,6 +684,12 @@ protected function _processExtendedAttribute($attribute)
621684 return array ('' , (array ) $ attribute ->val ());
622685 }
623686
687+ // We don't use model? Can't do nothing for you.
688+ if (! $ this ->_useModel )
689+ {
690+ return array ('' , (array ) $ attribute );
691+ }
692+
624693 // 1)
625694 list ($ relations , $ attribute ) = $ this ->separateAttributeFromRelations ($ attribute );
626695
0 commit comments