Skip to content

Commit 3547e7a

Browse files
committed
Merge branch 'release-1.2.8'
2 parents 1be3340 + adcb9ed commit 3547e7a

39 files changed

+752
-289
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class User extends SimpleAR\Model
264264
{
265265
...
266266

267-
protected $_columns = array(
267+
protected static $_columns = array(
268268
'last_name',
269269
'first_name',
270270
'age',
@@ -279,7 +279,7 @@ class User extends SimpleAR\Model
279279
{
280280
...
281281

282-
protected $_columns = array(
282+
protected static $_columns = array(
283283
'last_name',
284284
'first_name',
285285
// “age” will be used for “years_since_birth” column.

lib/Database/Builder.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,9 @@ public function addValueToQuery($value, $component = '')
220220
{
221221
if ($component)
222222
{
223-
if (! $value instanceof Expression)
224-
{
225-
$this->_values[$component][] = $value;
226-
}
223+
// Any check on value type (Model instance, Expression...) is made
224+
// in Query::prepareValuesForExecution().
225+
$this->_values[$component][] = $value;
227226
}
228227
else
229228
{

lib/Database/Builder/DeleteBuilder.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@ public function root($root)
2121
$this->_components['deleteFrom'] = $root; return;
2222
}
2323

24-
// We *have to* set the alias and not the table name. Since this is the
25-
// root that we are setting, we know its place in the arborescence.
26-
// Thus, we just have to generate its alias out of the table name.
27-
$tableAlias = $this->_getAliasForTableName($this->_table->name);
28-
$this->_components['deleteFrom'] = $tableAlias;
24+
// Using several tables is not yet possible with delete builder. Thus,
25+
// we set the table name in "deleteFrom" component. We won't bother with
26+
// any table alias.
27+
$this->_components['deleteFrom'] = $this->_table->name;
2928
}
3029
}

lib/Database/Builder/SelectBuilder.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,29 @@ public function offset($offset)
118118
/**
119119
* Eager load another table.
120120
*
121-
* If if you give a deep relation to eager load, columns of every middle
121+
* If you give a deep relation to eager load, columns of every middle
122122
* tables will be selected. For example, if you do:
123123
*
124124
* `$builder->with('articles/author')`
125125
*
126126
* authors' *and* articles' columns will be selected.
127127
*
128-
* @param string $relation The model relation name relative to the root
129-
* model.
128+
* @param string|array $relation The model relation name relative to the root
129+
* model *or* an array of relation names.
130130
*/
131131
public function with($relation)
132132
{
133+
// Handle multiple relations.
134+
if (is_array($relation))
135+
{
136+
foreach ($relation as $rel)
137+
{
138+
$this->with($rel);
139+
}
140+
141+
return $this;
142+
}
143+
133144
// We have two things to do:
134145
// 1) Include related table;
135146
// 2) Select related table columns.

lib/Database/Builder/UpdateBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function root($root)
2323
$this->_components['updateFrom'] = $root; return;
2424
}
2525

26-
$joinClause = new JoinClause($this->_table->name, '');
26+
$joinClause = new JoinClause($this->_table->name, $this->getRootAlias());
2727
$this->_components['updateFrom'] = array($joinClause);
2828

2929
return $this;

lib/Database/Builder/WhereBuilder.php

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
<?php namespace SimpleAR\Database\Builder;
22

33
use \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;
94
use \SimpleAR\Database\Expression;
105
use \SimpleAR\Database\JoinClause;
116
use \SimpleAR\Database\Query;
12-
137
use \SimpleAR\Exception\MalformedOptionException;
148
use \SimpleAR\Exception;
15-
169
use \SimpleAR\Facades\Cfg;
1710
use \SimpleAR\Facades\DB;
18-
1911
use \SimpleAR\Orm\Relation;
12+
use \SimpleAR\Orm\Relation\ManyMany;
2013
use \SimpleAR\Orm\Table;
2114

2215
class 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

lib/Database/Compiler.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<?php namespace SimpleAR\Database;
22

3-
require __DIR__ . '/Compiler/InsertCompiler.php';
4-
53
use \SimpleAR\Database\Query;
64
use \SimpleAR\Database\Expression;
75

@@ -14,13 +12,16 @@ abstract class Compiler
1412
* raw table name given in constructor. In this case, we would not be able to
1513
* use many features like process query on linked models.
1614
*
17-
* Property's value is set when starting the compilation step. Each public
18-
* compile can decide whether to use table alias or not depending on number
15+
* Property's value is set when starting the compilation step. Each public
16+
* compile can decide whether to use table alias or not depending on number
1917
* of used tables or things like that.
2018
*
19+
* If $useTableAlias is null when compilation starts, the compiler will
20+
* decide himself whether to use table aliases or not.
21+
*
2122
* @var bool
2223
*/
23-
public $useTableAlias = false;
24+
public $useTableAlias = null;
2425

2526
public $useResultAlias = false;
2627

@@ -166,6 +167,17 @@ protected function _compileAlias($identifier, $alias = '')
166167
*/
167168
public function parameterize($value)
168169
{
170+
// This allows users to directly pass object or object array as
171+
// a condition value.
172+
//
173+
// The same check is done in Compiler to correctly construct
174+
// query.
175+
// @see SimpleAR\Database\Compiler::parameterize()
176+
if ($value instanceof \SimpleAR\Orm\Model)
177+
{
178+
$value = $value->id();
179+
}
180+
169181
if (is_array($value))
170182
{
171183
// This line is taken from:

0 commit comments

Comments
 (0)