Skip to content

Commit

Permalink
Merge pull request #134 from auraphp/3.x-named-placeholders-only
Browse files Browse the repository at this point in the history
3.x: Named placeholders only for where() et al. conditions
  • Loading branch information
Paul M. Jones authored Mar 22, 2017
2 parents 3be4c85 + 0328669 commit 98a986d
Show file tree
Hide file tree
Showing 16 changed files with 173 additions and 319 deletions.
104 changes: 17 additions & 87 deletions src/AbstractQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,44 +65,17 @@ abstract class AbstractQuery
*/
protected $quoter;

/**
*
* Prefix to use on placeholders for "sequential" bound values; used for
* deconfliction when merging bound values from sub-selects, etc.
*
* @var mixed
*
*/
protected $seq_bind_prefix = '';

/**
*
* Constructor.
*
* @param Quoter $quoter A helper for quoting identifier names.
*
* @param string $seq_bind_prefix A prefix for rewritten sequential-binding
* placeholders (@see getSeqPlaceholder()).
*
*/
public function __construct(QuoterInterface $quoter, $builder, $seq_bind_prefix = '')
public function __construct(QuoterInterface $quoter, $builder)
{
$this->quoter = $quoter;
$this->builder = $builder;
$this->seq_bind_prefix = $seq_bind_prefix;
}

/**
*
* Returns the prefix for rewritten sequential-binding placeholders
* (@see getSeqPlaceholder()).
*
* @return string
*
*/
public function getSeqBindPrefix()
{
return $this->seq_bind_prefix;
}

/**
Expand Down Expand Up @@ -270,28 +243,6 @@ public function resetFlags()
return $this;
}

/**
*
* Adds a WHERE condition to the query by AND or OR. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $andor Add the condition using this operator, typically
* 'AND' or 'OR'.
*
* @param string $cond The WHERE condition.
*
* @param array ...$bind arguments to bind to placeholders
*
* @return $this
*
*/
protected function addWhere($andor, $cond, ...$bind)
{
$this->addClauseCondWithBind('where', $andor, $cond, $bind);
return $this;
}

/**
*
* Adds conditions and binds values to a clause.
Expand All @@ -303,17 +254,17 @@ protected function addWhere($andor, $cond, ...$bind)
* 'AND' or 'OR'.
*
* @param string $cond The WHERE condition.
*
* @param array $bind arguments to bind to placeholders
*
* @return null
*
*/
protected function addClauseCondWithBind($clause, $andor, $cond, $bind)
{
$cond = $this->quoter->quoteNamesIn($cond);
$cond = $this->rebuildCondAndBindValues($cond, $bind);

// add condition to clause; eg $this->where or $this->having
$clause =& $this->$clause;
if ($clause) {
$clause[] = "$andor $cond";
Expand All @@ -338,49 +289,28 @@ protected function addClauseCondWithBind($clause, $andor, $cond, $bind)
*/
protected function rebuildCondAndBindValues($cond, array $bind_values)
{
$cond = $this->quoter->quoteNamesIn($cond);

// bind values against ?-mark placeholders, but because PDO is finicky
// about the numbering of sequential placeholders, convert each ?-mark
// to a named placeholder
$parts = preg_split('/(\?)/', $cond, null, PREG_SPLIT_DELIM_CAPTURE);
foreach ($parts as $key => $val) {
if ($val != '?') {
continue;
}
$selects = [];

$bind_value = array_shift($bind_values);
if ($bind_value instanceof SelectInterface) {
$parts[$key] = $bind_value->getStatement();
$this->bind_values = array_merge(
$this->bind_values,
$bind_value->getBindValues()
);
continue;
foreach ($bind_values as $key => $val) {
if ($val instanceof SelectInterface) {
$selects[":{$key}"] = $val;
} else {
$this->bindValue($key, $val);
}
}

$placeholder = $this->getSeqPlaceholder();
$parts[$key] = ':' . $placeholder;
$this->bind_values[$placeholder] = $bind_value;
foreach ($selects as $key => $select) {
$selects[$key] = $select->getStatement();
$this->bind_values = array_merge(
$this->bind_values,
$select->getBindValues()
);
}

$cond = implode('', $parts);
$cond = strtr($cond, $selects);
return $cond;
}

/**
*
* Gets the current sequential placeholder name.
*
* @return string
*
*/
protected function getSeqPlaceholder()
{
$i = count($this->bind_values) + 1;
return $this->seq_bind_prefix . "_{$i}_";
}

/**
*
* Adds a column order to the query.
Expand Down
16 changes: 6 additions & 10 deletions src/Common/Select.php
Original file line number Diff line number Diff line change
Expand Up @@ -635,39 +635,35 @@ public function groupBy(array $spec)

/**
*
* Adds a HAVING condition to the query by AND. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
* Adds a HAVING condition to the query by AND.
*
* @param string $cond The HAVING condition.
*
* @param array ...$bind arguments to bind to placeholders
* @param array $bind arguments to bind to placeholders
*
* @return $this
*
*/
public function having($cond, ...$bind)
public function having($cond, array $bind = [])
{
$this->addClauseCondWithBind('having', 'AND', $cond, $bind);
return $this;
}

/**
*
* Adds a HAVING condition to the query by AND. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
* Adds a HAVING condition to the query by OR.
*
* @param string $cond The HAVING condition.
*
* @param array ...$bind arguments to bind to placeholders
* @param array $bind arguments to bind to placeholders
*
* @return $this
*
* @see having()
*
*/
public function orHaving($cond, ...$bind)
public function orHaving($cond, array $bind = [])
{
$this->addClauseCondWithBind('having', 'OR', $cond, $bind);
return $this;
Expand Down
29 changes: 6 additions & 23 deletions src/Common/SelectInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,48 +244,31 @@ public function groupBy(array $spec);

/**
*
* Adds a HAVING condition to the query by AND; if a value is passed as
* the second param, it will be quoted and replaced into the condition
* wherever a question-mark appears.
*
* Array values are quoted and comma-separated.
*
* {{code: php
* // simplest but non-secure
* $select->having("COUNT(id) = $count");
*
* // secure
* $select->having('COUNT(id) = ?', $count);
*
* // equivalent security with named binding
* $select->having('COUNT(id) = :count');
* $select->bind('count', $count);
* }}
* Adds a HAVING condition to the query by AND.
*
* @param string $cond The HAVING condition.
*
* @param array ...$bind arguments to bind to placeholders
* @param array $bind Values to be bound to placeholders.
*
* @return $this
*
*/
public function having($cond, ...$bind);
public function having($cond, array $bind = []);

/**
*
* Adds a HAVING condition to the query by AND; otherwise identical to
* `having()`.
* Adds a HAVING condition to the query by OR.
*
* @param string $cond The HAVING condition.
*
* @param array ...$bind arguments to bind to placeholders
* @param array $bind Values to be bound to placeholders.
*
* @return $this
*
* @see having()
*
*/
public function orHaving($cond, ...$bind);
public function orHaving($cond, array $bind = []);

/**
*
Expand Down
10 changes: 6 additions & 4 deletions src/Common/WhereInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ interface WhereInterface
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to be bound to placeholders
*
* @param array $bind Values to be bound to placeholders.
*
* @return $this
*
*/
public function where($cond, ...$bind);
public function where($cond, array $bind = []);

/**
*
Expand All @@ -38,12 +39,13 @@ public function where($cond, ...$bind);
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to be bound to placeholders
*
* @param array $bind Values to be bound to placeholders.
*
* @return $this
*
* @see where()
*
*/
public function orWhere($cond, ...$bind);
public function orWhere($cond, array $bind = []);
}
34 changes: 9 additions & 25 deletions src/Common/WhereTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,18 @@ trait WhereTrait
{
/**
*
* Adds a WHERE condition to the query by AND. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
* Adds a WHERE condition to the query by AND.
*
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to be bound to placeholders
*
* @param array $bind Values to be bound to placeholders
*
* @return $this
*
*/
public function where($cond, ...$bind)
public function where($cond, array $bind = [])
{
$this->addWhere('AND', $cond, ...$bind);
$this->addClauseCondWithBind('where', 'AND', $cond, $bind);
return $this;
}

Expand All @@ -42,32 +41,17 @@ public function where($cond, ...$bind)
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to be bound to placeholders
*
* @param array $bind Values to be bound to placeholders
*
* @return $this
*
* @see where()
*
*/
public function orWhere($cond, ...$bind)
public function orWhere($cond, array $bind = [])
{
$this->addWhere('OR', $cond, ...$bind);
$this->addClauseCondWithBind('where', 'OR', $cond, $bind);
return $this;
}

/**
*
* Adds a WHERE condition to the query by AND or OR. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $andor Add the condition using this operator, typically
* 'AND' or 'OR'.
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to bind to placeholders
*
* @return $this
*
*/
abstract protected function addWhere($andor, $cond, ...$bind);
}
Loading

0 comments on commit 98a986d

Please sign in to comment.