Skip to content

Commit 3b228fd

Browse files
committed
Adding a possibility to bypass MagicParameter
1 parent e3b6682 commit 3b228fd

File tree

5 files changed

+49
-7
lines changed

5 files changed

+49
-7
lines changed

doc/discard_unused_parameters.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,28 @@ $magicQuery = new MagicQuery();
6565
$sql = $magicQuery->build($sql, $params);
6666
```
6767

68+
####Forcing some parameters to be null
69+
70+
MagicQuery assumes that if a parameter is null, you want to completely remove the code related to this
71+
parameter from the SQL.
72+
73+
But sometimes, you actually want to test parameters against the NULL value.
74+
In those cases, you need to disable the MagicParameter feature of MagicQuery for those parameters.
75+
76+
<div class="alert alert-info">To disable MagicParameter for a given parameter, simply add an exclamation
77+
mark (!) after the parameter name.</div>
78+
79+
```php
80+
// This query uses twice the "status" parameter. Once with ! and once without
81+
$sql = "SELECT * FROM products p WHERE status1 = :status AND status2 = :status!";
82+
83+
$magicQuery = new MagicQuery();
84+
// We don't pass the "status" parameter
85+
$sql = $magicQuery->build($sql, []);
86+
// The part "status1 = :status" is discarded, but the part "status2 = :status!" is kept
87+
// $sql == "SELECT * FROM products p WHERE status2 = null"
88+
```
89+
6890
###Other alternatives
6991

7092
To avoid concatenating strings, frameworks and libraries have used different strategies. Using a full ORM (like

src/Mouf/Database/MagicQuery.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function __construct($connection = null, $cache = null, SchemaAnalyzer $s
5858
* @return $this
5959
*/
6060
public function setEnableTwig($enableTwig = true) {
61-
$this->enableTwig = true;
61+
$this->enableTwig = $enableTwig;
6262
return $this;
6363
}
6464

src/SQLParser/Node/AbstractTwoOperandsOperator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ public function toSql(array $parameters = array(), Connection $dbConnection = nu
101101
if ($conditionsMode == self::CONDITION_GUESS) {
102102
$bypass = false;
103103
if ($this->leftOperand instanceof Parameter) {
104-
if (!isset($parameters[$this->leftOperand->getName()])) {
104+
if ($this->leftOperand->isDiscardedOnNull() && !isset($parameters[$this->leftOperand->getName()])) {
105105
$bypass = true;
106106
}
107107
}
108108
if ($this->rightOperand instanceof Parameter) {
109-
if (!isset($parameters[$this->rightOperand->getName()])) {
109+
if ($this->rightOperand->isDiscardedOnNull() && !isset($parameters[$this->rightOperand->getName()])) {
110110
$bypass = true;
111111
}
112112
}

src/SQLParser/Node/Parameter.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@
4646
class Parameter implements NodeInterface
4747
{
4848
private $name;
49+
private $discardedOnNull = true;
4950

5051
/**
51-
* Returns the name name.
52+
* Returns the name.
5253
*
5354
* @return string
5455
*/
@@ -58,15 +59,22 @@ public function getName()
5859
}
5960

6061
/**
61-
* Sets the name name.
62+
* Sets the name.
63+
* If the name ends with !, the parameter will be considered not nullable (regarding magicparameter settings)
6264
*
6365
* @Important
6466
*
6567
* @param string $name
6668
*/
6769
public function setName($name)
6870
{
69-
$this->name = $name;
71+
if (strrpos($name, '!') === strlen($name)-1) {
72+
$this->name = substr($name, 0, strlen($name)-1);
73+
$this->discardedOnNull = false;
74+
} else {
75+
$this->name = $name;
76+
$this->discardedOnNull = true;
77+
}
7078
}
7179

7280
/**
@@ -177,6 +185,8 @@ public function toSql(array $parameters = array(), Connection $dbConnection = nu
177185

178186
}
179187
}
188+
} elseif (!$this->isDiscardedOnNull()) {
189+
return 'null';
180190
} else {
181191
return ':'.$this->name;
182192
}
@@ -196,4 +206,12 @@ public function walk(VisitorInterface $visitor) {
196206
}
197207
return $visitor->leaveNode($node);
198208
}
209+
210+
/**
211+
* Returns whether the parameter can be discarded if provided value is null.
212+
* @return bool
213+
*/
214+
public function isDiscardedOnNull() {
215+
return $this->discardedOnNull;
216+
}
199217
}

tests/Mouf/Database/MagicQueryTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ public function testStandardSelect()
3636
$sql = 'SELECT id+1 FROM users';
3737
$this->assertEquals("SELECT id + '1' FROM users", self::simplifySql($magicQuery->build($sql)));
3838

39-
39+
// Tests parameters with a ! (to force NULL values)
40+
$sql = 'SELECT * FROM users WHERE status = :status!';
41+
$this->assertEquals("SELECT * FROM users WHERE status = null", self::simplifySql($magicQuery->build($sql, ['status' => null])));
4042
}
4143

4244
public function testWithCache() {

0 commit comments

Comments
 (0)