Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added orWhere method #9

Merged
merged 1 commit into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities

## [5.1.0] - 2024.10.05

### Added

- Added `orWhere` method.

## [5.0.0] - 2024.09.16

### Added
Expand Down
27 changes: 26 additions & 1 deletion docs/query-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ $query = new Query($pdo); // $pdo as a PDO instance
- [rightjoin](#rightjoin)
- [select](#select)
- [where](#where)
- [orWhere](#orwhere)
- [orderBy](#orderby)
- [orderByRand](#orderbyrand)
- [limit](#limit)
Expand Down Expand Up @@ -156,7 +157,7 @@ JSON fields which do not exist are returned with a value of `null`.

**Description:**

Adds a `WHERE` clause to the query.
Adds a `WHERE/AND WHERE` clause to the query.

If the column type is `JSON`, keys from within the JSON string can be searched with the format of `COLUMN->KEY`.
JSON fields which do not exist are treated as `null`.
Expand Down Expand Up @@ -205,6 +206,30 @@ The `VALUE_*` constants can be used for this purpose.

<hr />

### orWhere

**Description:**

Adds an `OR/AND OR` clause to the query.

See [where](#where).

**Parameters:**

- `$column` (string)
- `$operator` (string)
- `$value` (mixed)

**Returns:**

- (self)

**Throws:**

- `Bayfront\SimplePdo\Exceptions\QueryException`

<hr />

### orderBy

**Description:**
Expand Down
178 changes: 110 additions & 68 deletions src/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,53 +267,24 @@ private function parseConditionColumn(string $column): string
public const VALUE_TRUE = 'true';
public const VALUE_FALSE = 'false';

private const CONDITION_AND = 'AND';
private const CONDITION_OR = 'OR';

/**
* Adds a WHERE clause to the query.
*
* If the column type is JSON, keys from within the JSON string can be searched with the format of COLUMN->KEY.
* JSON fields which do not exist are treated as null.
*
* Available operators are:
*
* - eq (equals)
* - !eq (does not equal)
* - lt (less than)
* - gt (greater than)
* - le (less than or equal to)
* - ge (greater than or equal to)
* - sw (starts with)
* - !sw (does not start with)
* - ew (ends with)
* - !ew (does not end with)
* - has (has)
* - !has (does not have)
* - in (in)
* - !in (not in)
* - null (is or is not null)
*
* The OPERATOR_* constants can be used for this purpose.
*
* The in and !in operators accept multiple comma-separated values.
*
* The "null" operator accepts two values: true and false for is null or is not null.
* The VALUE_* constants can be used for this purpose.
*
* NOTE: Some native MySQL functions can be used as the $value, however, they will be
* injected into the query as strings, so they can be vulnerable to SQL injection.
*
* @param string $condition (and/or)
* @param string $column
* @param string $operator
* @param mixed $value
* @return self
* @param $value
* @return void
* @throws QueryException
*/
public function where(string $column, string $operator, mixed $value): self
private function addCondition(string $condition, string $column, string $operator, $value): void
{

if (!isset($this->query[self::QUERY_WHERE])) {
$this->query[self::QUERY_WHERE] = ' WHERE ';
$condition = ' WHERE (';
} else {
$this->query[self::QUERY_WHERE] .= ' AND ';
$condition = ' ' . $condition . ' (';
}

if (!in_array($operator, [
Expand Down Expand Up @@ -356,78 +327,80 @@ public function where(string $column, string $operator, mixed $value): self

// Check operators

$placeholders = [];

switch ($operator) {

case self::OPERATOR_STARTS_WITH:

if ($this->is_function($value)) {
$this->query[self::QUERY_WHERE] .= $column . ' LIKE ' . $value;
$condition .= $column . ' LIKE ' . $value;
break;
}

$this->placeholders[] = $value . '%';
$this->query[self::QUERY_WHERE] .= $column . ' LIKE ?';
$placeholders[] = $value . '%';
$condition .= $column . ' LIKE ?';
break;

case self::OPERATOR_DOES_NOT_START_WITH:

if ($this->is_function($value)) {
$this->query[self::QUERY_WHERE] .= $column . ' NOT LIKE ' . $value;
$condition .= $column . ' NOT LIKE ' . $value;
break;
}

$this->placeholders[] = $value . '%';
$this->query[self::QUERY_WHERE] .= $column . ' NOT LIKE ?';
$placeholders[] = $value . '%';
$condition .= $column . ' NOT LIKE ?';
break;

case self::OPERATOR_ENDS_WITH:

if ($this->is_function($value)) {
$this->query[self::QUERY_WHERE] .= $column . ' LIKE ' . $value;
$condition .= $column . ' LIKE ' . $value;
break;
}

$this->placeholders[] = '%' . $value;
$this->query[self::QUERY_WHERE] .= $column . ' LIKE ?';
$placeholders[] = '%' . $value;
$condition .= $column . ' LIKE ?';
break;

case self::OPERATOR_DOES_NOT_END_WITH:

if ($this->is_function($value)) {
$this->query[self::QUERY_WHERE] .= $column . ' NOT LIKE ' . $value;
$condition .= $column . ' NOT LIKE ' . $value;
break;
}

$this->placeholders[] = '%' . $value;
$this->query[self::QUERY_WHERE] .= $column . ' NOT LIKE ?';
$placeholders[] = '%' . $value;
$condition .= $column . ' NOT LIKE ?';
break;

case self::OPERATOR_HAS:

if ($this->is_function($value)) {
$this->query[self::QUERY_WHERE] .= $column . ' LIKE ' . $value;
$condition .= $column . ' LIKE ' . $value;
break;
}

$this->placeholders[] = '%' . $value . '%';
$this->query[self::QUERY_WHERE] .= $column . ' LIKE ?';
$placeholders[] = '%' . $value . '%';
$condition .= $column . ' LIKE ?';
break;

case self::OPERATOR_DOES_NOT_HAVE:

if ($this->is_function($value)) {
$this->query[self::QUERY_WHERE] .= $column . ' NOT LIKE ' . $value;
$condition .= $column . ' NOT LIKE ' . $value;
break;
}

$this->placeholders[] = '%' . $value . '%';
$this->query[self::QUERY_WHERE] .= $column . ' NOT LIKE ?';
$placeholders[] = '%' . $value . '%';
$condition .= $column . ' NOT LIKE ?';
break;

case self::OPERATOR_IN:

if ($this->is_function($value)) {
$this->query[self::QUERY_WHERE] .= $column . ' IN (' . $value . ')';
$condition .= $column . ' IN (' . $value . ')';
break;
}

Expand All @@ -437,18 +410,18 @@ public function where(string $column, string $operator, mixed $value): self

foreach ($in_values as $val) {

$this->placeholders[] = $val;
$placeholders[] = $val;

}

$this->query[self::QUERY_WHERE] .= $column . ' IN (' . $in . ')';
$condition .= $column . ' IN (' . $in . ')';

break;

case self::OPERATOR_NOT_IN:

if ($this->is_function($value)) {
$this->query[self::QUERY_WHERE] .= $column . ' NOT IN (' . $value . ')';
$condition .= $column . ' NOT IN (' . $value . ')';
break;
}

Expand All @@ -458,23 +431,23 @@ public function where(string $column, string $operator, mixed $value): self

foreach ($in_values as $val) {

$this->placeholders[] = $val;
$placeholders[] = $val;

}

$this->query[self::QUERY_WHERE] .= $column . ' NOT IN (' . $in . ')';
$condition .= $column . ' NOT IN (' . $in . ')';

break;

case self::OPERATOR_NULL:

if ($value == self::VALUE_TRUE) {

$this->query[self::QUERY_WHERE] .= $column . ' IS NULL';
$condition .= $column . ' IS NULL';

} else if ($value == self::VALUE_FALSE) {

$this->query[self::QUERY_WHERE] .= $column . ' IS NOT NULL';
$condition .= $column . ' IS NOT NULL';

} else {

Expand All @@ -488,23 +461,92 @@ public function where(string $column, string $operator, mixed $value): self

if ($value == '') { // Empty string needs no placeholder

$this->query[self::QUERY_WHERE] .= $column . " " . $operator . " ''";
$condition .= $column . " " . $operator . " ''";

} else if ($this->is_function($value)) {

$this->query[self::QUERY_WHERE] .= $column . ' ' . $operator . ' ' . $value;
$condition .= $column . ' ' . $operator . ' ' . $value;

} else {

$this->placeholders[] = $value;
$this->query[self::QUERY_WHERE] .= $column . ' ' . $operator . ' ?';
$placeholders[] = $value;
$condition .= $column . ' ' . $operator . ' ?';

}

}

if (!isset($this->query[self::QUERY_WHERE])) {
$this->query[self::QUERY_WHERE] = $condition . ')';
} else {
$this->query[self::QUERY_WHERE] .= $condition . ')';
}

$this->placeholders = array_merge($this->placeholders, $placeholders);

}

/**
* Adds a WHERE/AND WHERE clause to the query.
*
* If the column type is JSON, keys from within the JSON string can be searched with the format of COLUMN->KEY.
* JSON fields which do not exist are treated as null.
*
* Available operators are:
*
* - eq (equals)
* - !eq (does not equal)
* - lt (less than)
* - gt (greater than)
* - le (less than or equal to)
* - ge (greater than or equal to)
* - sw (starts with)
* - !sw (does not start with)
* - ew (ends with)
* - !ew (does not end with)
* - has (has)
* - !has (does not have)
* - in (in)
* - !in (not in)
* - null (is or is not null)
*
* The OPERATOR_* constants can be used for this purpose.
*
* The in and !in operators accept multiple comma-separated values.
*
* The "null" operator accepts two values: true and false for is null or is not null.
* The VALUE_* constants can be used for this purpose.
*
* NOTE: Some native MySQL functions can be used as the $value, however, they will be
* injected into the query as strings, so they can be vulnerable to SQL injection.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @return self
* @throws QueryException
*/
public function where(string $column, string $operator, mixed $value): self
{
$this->addCondition(self::CONDITION_AND, $column, $operator, $value);
return $this;
}

/**
* Adds an OR/AND OR clause to the query.
*
* See where().
*
* @param string $column
* @param string $operator
* @param mixed $value
* @return $this
* @throws QueryException
*/
public function orWhere(string $column, string $operator, mixed $value): self
{
$this->addCondition(self::CONDITION_OR, $column, $operator, $value);
return $this;
}

/**
Expand Down