20250801
This commit is contained in:
158
sources/classes/Condition.php
Normal file
158
sources/classes/Condition.php
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\classes;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\classes\Tuple;
|
||||||
|
use goodboyalex\php_components_pack\interfaces\IArrayable;
|
||||||
|
use PHPUnit\Event\InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Условие запроса выборки по условию.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_db_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class Condition implements IArrayable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Оператор логического И.
|
||||||
|
*/
|
||||||
|
public const string LOGIC_AND = 'AND';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Оператор логического ИЛИ.
|
||||||
|
*/
|
||||||
|
public const string LOGIC_OR = 'OR';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Оператор логического НЕ.
|
||||||
|
*/
|
||||||
|
public const string LOGIC_NOT = 'NOT';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Оператор логического ИСКЛЮЧАЮЩЕГО ИЛИ.
|
||||||
|
*/
|
||||||
|
public const string LOGIC_XOR = 'XOR';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Оператор логического НЕ И.
|
||||||
|
*/
|
||||||
|
public const string LOGIC_NAND = 'NAND';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Оператор логического НЕ ИЛИ.
|
||||||
|
*/
|
||||||
|
public const string LOGIC_NOR = 'NOR';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $ColumnName Имя колонки.
|
||||||
|
*/
|
||||||
|
private string $ColumnName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $Operator Оператор.
|
||||||
|
*/
|
||||||
|
private string $Operator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var mixed $Value Значение.
|
||||||
|
*/
|
||||||
|
private mixed $Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор.
|
||||||
|
*
|
||||||
|
* @param string $columnName Имя колонки.
|
||||||
|
* @param string $operator Оператор.
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*/
|
||||||
|
public function __construct (string $columnName = "", string $operator = "=", mixed $value = null)
|
||||||
|
{
|
||||||
|
$this->ColumnName = $columnName;
|
||||||
|
$this->Operator = $operator;
|
||||||
|
$this->Value = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Разбирает условие, заданное массивом и возвращает объект <code>Condition</code>.
|
||||||
|
*
|
||||||
|
* @param array $condition Условие, заданное в массиве.
|
||||||
|
*
|
||||||
|
* @return Condition Условие.
|
||||||
|
*/
|
||||||
|
public static function Parse (array $condition): Condition
|
||||||
|
{
|
||||||
|
// Проверка условия
|
||||||
|
if (count($condition) < 3)
|
||||||
|
// - если условие не содержит 3 элемента, то выбрасывается исключение
|
||||||
|
throw new InvalidArgumentException('Неверный формат условия / Unexpected condition format.');
|
||||||
|
|
||||||
|
// Разбор условия
|
||||||
|
[$column, $operator, $value] = $condition;
|
||||||
|
|
||||||
|
// Создание условия
|
||||||
|
return new Condition($column, $operator, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Формирует условие.
|
||||||
|
*
|
||||||
|
* @param int $index Индекс замены параметров для защиты от SQL-инъекций.
|
||||||
|
*
|
||||||
|
* @return Tuple (string, array) Сформированное условие: SQL-запрос и параметры запроса.
|
||||||
|
*/
|
||||||
|
public function Get (int $index = 0): Tuple
|
||||||
|
{
|
||||||
|
// Формирование условия SQL
|
||||||
|
$sql = "`$this->ColumnName` $this->Operator :prop_$index";
|
||||||
|
|
||||||
|
// Формирование параметров запроса
|
||||||
|
$params = [":prop_$index" => $this->Value];
|
||||||
|
|
||||||
|
// Возвращение результата
|
||||||
|
return new Tuple($sql, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function ToArray (): array
|
||||||
|
{
|
||||||
|
// Создаю массив
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Заполняю его
|
||||||
|
$result["type_class"] = Condition::class;
|
||||||
|
$result["ColumnName"] = $this->ColumnName;
|
||||||
|
$result["Operator"] = $this->Operator;
|
||||||
|
$result["Value"] = $this->Value;
|
||||||
|
|
||||||
|
// Возвращаю массив
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function FromArray (array $array): void
|
||||||
|
{
|
||||||
|
// Проверка массива
|
||||||
|
// - если массив содержит элемент "ColumnName"
|
||||||
|
if (isset($array["ColumnName"]))
|
||||||
|
// -- то присваиваю его значение
|
||||||
|
$this->ColumnName = $array["ColumnName"];
|
||||||
|
|
||||||
|
// - если массив содержит элемент "Operator"
|
||||||
|
if (isset($array["Operator"]))
|
||||||
|
// -- то присваиваю его значение
|
||||||
|
$this->Operator = $array["Operator"];
|
||||||
|
|
||||||
|
// - если массив содержит элемент "Value"
|
||||||
|
if (isset($array["Value"]))
|
||||||
|
// -- то присваиваю его значение
|
||||||
|
$this->Value = $array["Value"];
|
||||||
|
}
|
||||||
|
}
|
415
sources/classes/ConditionBuilder.php
Normal file
415
sources/classes/ConditionBuilder.php
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\classes;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\classes\Tuple;
|
||||||
|
use goodboyalex\php_components_pack\extensions\ArrayExtension;
|
||||||
|
use goodboyalex\php_components_pack\interfaces\IArrayable;
|
||||||
|
use goodboyalex\php_db_components_pack\traits\ConditionBuilder\ConditionBuilderConditionsSet;
|
||||||
|
use goodboyalex\php_db_components_pack\traits\ConditionBuilder\ConditionBuilderLogicalOperationSet;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Построитель условий запроса выборки.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class ConditionBuilder implements IArrayable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array $Conditions Массив условий.
|
||||||
|
*/
|
||||||
|
private array $Conditions = [];
|
||||||
|
|
||||||
|
// Задание цепочки условий
|
||||||
|
use ConditionBuilderConditionsSet;
|
||||||
|
|
||||||
|
// Задание цепочки логических операций
|
||||||
|
use ConditionBuilderLogicalOperationSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Создает объект для построения условий запроса выборки по массиву условий.
|
||||||
|
*
|
||||||
|
* Пример:
|
||||||
|
*
|
||||||
|
* ["id" => 1, 'AND', "age" => ['>=', 18], 'OR', "profile" => ['<=', 12], 'AND', ['AND', "Name" => "Alex",
|
||||||
|
* ['OR', "Age" => ['>', 18], "FirstName" => "Titanic"]]]
|
||||||
|
*
|
||||||
|
* задаёт следующий массив условий:
|
||||||
|
*
|
||||||
|
* `id` = 1 AND `age` >= 18 OR `profile` <= 12 AND (`Name` = 'Alex' AND (`Age` > 18 OR `FirstName` =
|
||||||
|
* 'Titanic'
|
||||||
|
*
|
||||||
|
* @param array $conditions Массив условий.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Объект построителя условий запроса выборки.
|
||||||
|
*/
|
||||||
|
public static function Parse (array $conditions): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Создаём объект для цепочки
|
||||||
|
$builder = new ConditionBuilder();
|
||||||
|
|
||||||
|
// Перебираем условия
|
||||||
|
foreach ($conditions as $key => $condition) {
|
||||||
|
// - если это индексированная часть массива
|
||||||
|
if (is_numeric($key)) {
|
||||||
|
// -- это может быть логический оператор? Проверим, является ли $condition строкой
|
||||||
|
if (is_string($condition)) {
|
||||||
|
// --- если да, то добавляем его в цепочку
|
||||||
|
$builder = $builder->AddLogicalOperator($condition);
|
||||||
|
|
||||||
|
// --- если ошибка
|
||||||
|
if ($builder === false)
|
||||||
|
// ---- то выбрасываем исключение
|
||||||
|
throw new InvalidArgumentException("Неверный логический оператор: $condition / The logical operator is invalid: $condition.");
|
||||||
|
|
||||||
|
// --- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- это группа условий, парсим её и добавляем результат
|
||||||
|
$builder = $builder->AddGroupA(self::ParseConditionGroup($condition));
|
||||||
|
|
||||||
|
// -- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - это условие, парсим его и добавляем результат
|
||||||
|
$builder = $builder->AddConditionA(self::ParseCondition($key, $condition));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, является ли оператор логическим, и возвращает правильно отформатированный оператор.
|
||||||
|
*
|
||||||
|
* @param string $operator Оператор.
|
||||||
|
*
|
||||||
|
* @return false|string Возвращает правильно отформатированный оператор или <code>false</code>, если оператор
|
||||||
|
* не является логическим.
|
||||||
|
*/
|
||||||
|
private static function PrepareLogicalOperator (string $operator): false|string
|
||||||
|
{
|
||||||
|
// Задаем массив логических операторов
|
||||||
|
$logicalOperators = ['AND', 'OR', 'NOT', 'XOR', 'NAND', 'NOR'];
|
||||||
|
|
||||||
|
// Переводим оператор в верхний регистр
|
||||||
|
$operator = strtoupper($operator);
|
||||||
|
|
||||||
|
// Если оператор не входит в массив логических операторов
|
||||||
|
if (!in_array($operator, $logicalOperators, true))
|
||||||
|
// - возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Возвращаем правильный оператор
|
||||||
|
return $operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обрабатывает условие, заданное в виде массива.
|
||||||
|
*
|
||||||
|
* @param string $column Имя столбца.
|
||||||
|
* @param mixed $conditions Условия.
|
||||||
|
*
|
||||||
|
* @return Condition Возвращает условие.
|
||||||
|
*/
|
||||||
|
private static function ParseCondition (string $column, mixed $conditions): Condition
|
||||||
|
{
|
||||||
|
// Проверяем условия
|
||||||
|
// - если это не массив
|
||||||
|
if (!is_array($conditions))
|
||||||
|
// -- то добавляем оператор равенства и обрабатываем как массив
|
||||||
|
$conditions = ['=', $conditions];
|
||||||
|
|
||||||
|
// - если это массив в массиве
|
||||||
|
if (is_array($conditions[0]))
|
||||||
|
// -- то извлекаем первый элемент, как весь массив
|
||||||
|
$conditions = $conditions[0];
|
||||||
|
|
||||||
|
// - если это массив с длинной меньше 2
|
||||||
|
if (count($conditions) < 2)
|
||||||
|
// -- то исправляем это
|
||||||
|
$conditions = array_merge(['='], $conditions);
|
||||||
|
|
||||||
|
// Добавляем условие
|
||||||
|
return new Condition($column, $conditions[0], $conditions[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обрабатывает группу условий.
|
||||||
|
*
|
||||||
|
* @param array $conditions Условия.
|
||||||
|
*
|
||||||
|
* @return ConditionGroup Возвращает группу условий.
|
||||||
|
*/
|
||||||
|
private static function ParseConditionGroup (array $conditions): ConditionGroup
|
||||||
|
{
|
||||||
|
// Получаем оператор
|
||||||
|
$operator = $conditions[0];
|
||||||
|
|
||||||
|
|
||||||
|
// Удаляем его из массива условий
|
||||||
|
$conditions = array_slice($conditions, 1);
|
||||||
|
|
||||||
|
// Задаем массив условий группы
|
||||||
|
$conditionItems = [];
|
||||||
|
|
||||||
|
// Перебираем условия
|
||||||
|
foreach ($conditions as $key => $condition) {
|
||||||
|
// - если это индексированная часть массива
|
||||||
|
if (is_numeric($key)) {
|
||||||
|
// -- то это группа условий, парсим её и добавляем результат
|
||||||
|
$conditionItems[] = self::ParseConditionGroup($condition);
|
||||||
|
|
||||||
|
// -- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если это не индексированная часть массива, то это условие, парсим его и добавляем результат
|
||||||
|
$conditionItems[] = self::ParseCondition($key, [$condition]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//var_dump($conditionItems);
|
||||||
|
|
||||||
|
// Возвращаем группу условий
|
||||||
|
return new ConditionGroup($operator, $conditionItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет группу условий.
|
||||||
|
*
|
||||||
|
* @param string $logicalOperator Оператор связок внутри группы.
|
||||||
|
* @param array $conditions Условия.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function AddGroup (string $logicalOperator, array $conditions): ConditionBuilder
|
||||||
|
{
|
||||||
|
return $this->AddGroupA(new ConditionGroup($logicalOperator, $conditions));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Собирает условие в виде строки.
|
||||||
|
*
|
||||||
|
* @return string Возвращает условие в виде, пригодном для SQL.
|
||||||
|
*/
|
||||||
|
public function Build (): Tuple
|
||||||
|
{
|
||||||
|
// Очищаем цепочку от пустых элементов
|
||||||
|
ArrayExtension::RemoveEmpties($this->Conditions);
|
||||||
|
|
||||||
|
// Парсим цепочку и возвращаем результат
|
||||||
|
return $this->ProcessConditions($this->Conditions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function ToArray (): array
|
||||||
|
{
|
||||||
|
// Задаем массив результата
|
||||||
|
$result = [
|
||||||
|
'type_class' => ConditionBuilder::class
|
||||||
|
];
|
||||||
|
|
||||||
|
// Перебираем условия
|
||||||
|
foreach ($this->Conditions as $condition) {
|
||||||
|
// - если это группа условий
|
||||||
|
if ($condition instanceof ConditionGroup) {
|
||||||
|
// -- парсим её и добавляем результат
|
||||||
|
$result['conditions'][] = $condition->ToArray();
|
||||||
|
|
||||||
|
// -- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если это условие
|
||||||
|
if ($condition instanceof Condition) {
|
||||||
|
// -- парсим его и добавляем результат
|
||||||
|
$result['conditions'][] = $condition->ToArray();
|
||||||
|
|
||||||
|
// -- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - иначе считаем, что это логический оператор
|
||||||
|
$result['conditions'][] = $condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function FromArray (array $array): void
|
||||||
|
{
|
||||||
|
// Удаляем тип класса
|
||||||
|
$preparedConditions = array_diff(['type_class' => ConditionBuilder::class], $array);
|
||||||
|
|
||||||
|
// Очищаем массив
|
||||||
|
$this->Conditions = [];
|
||||||
|
|
||||||
|
// Перебираем условия
|
||||||
|
foreach ($preparedConditions as $condition) {
|
||||||
|
// - получаем тип
|
||||||
|
$type = (isset($condition['type_class'])) ? $condition['type_class'] : "";
|
||||||
|
|
||||||
|
// - если это группа условий
|
||||||
|
if ($type == ConditionGroup::class) {
|
||||||
|
// -- создаём объект
|
||||||
|
$conditionGroup = new ConditionGroup();
|
||||||
|
|
||||||
|
// -- восстанавливаем его из массива
|
||||||
|
$conditionGroup->FromArray($condition);
|
||||||
|
|
||||||
|
// -- добавляем его в цепочку
|
||||||
|
$this->Conditions[] = $conditionGroup;
|
||||||
|
|
||||||
|
// -- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если это условие
|
||||||
|
if ($type == Condition::class) {
|
||||||
|
// -- создаём объект
|
||||||
|
$conditionGroup = new Condition();
|
||||||
|
|
||||||
|
// -- восстанавливаем его из массива
|
||||||
|
$conditionGroup->FromArray($condition);
|
||||||
|
|
||||||
|
// -- добавляем его в цепочку
|
||||||
|
$this->Conditions[] = $conditionGroup;
|
||||||
|
|
||||||
|
// -- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - иначе считаем, что это логический оператор
|
||||||
|
$this->Conditions[] = $condition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получает количество условий в цепочке.
|
||||||
|
*
|
||||||
|
* @return int Возвращает количество условий.
|
||||||
|
*/
|
||||||
|
public function Count (): int
|
||||||
|
{
|
||||||
|
// Задаем счетчик
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
// Перебираем условия
|
||||||
|
foreach ($this->Conditions as $condition) {
|
||||||
|
// - если это условие
|
||||||
|
if ($condition instanceof Condition)
|
||||||
|
// -- то сразу увеличиваем счетчик
|
||||||
|
$count++;
|
||||||
|
|
||||||
|
// - если это группа условий
|
||||||
|
if ($condition instanceof ConditionGroup)
|
||||||
|
// -- то считаем их количество и добавляем к счетчику
|
||||||
|
$count += $condition->Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет группу условий.
|
||||||
|
*
|
||||||
|
* @param ConditionGroup $group Группа условий.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
private function AddGroupA (ConditionGroup $group): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = $group;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Собирает условие в виде, пригодном для SQL.
|
||||||
|
*
|
||||||
|
* @param array $conditions Условия.
|
||||||
|
*
|
||||||
|
* @return Tuple (string, array) Возвращает условие в виде, пригодном для SQL и массив параметров для защиты
|
||||||
|
* от SQL-инъекций.
|
||||||
|
*/
|
||||||
|
private function ProcessConditions (array $conditions): Tuple
|
||||||
|
{
|
||||||
|
// Задаём массив частей
|
||||||
|
$parts = [];
|
||||||
|
|
||||||
|
// Задаём массив параметров для защиты от SQL-инъекций
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
// Задаём счётчик
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
// Перебираем условия
|
||||||
|
foreach ($conditions as $condition) {
|
||||||
|
// - если это группа условий
|
||||||
|
if ($condition instanceof ConditionGroup) {
|
||||||
|
// -- парсим её и добавляем результат
|
||||||
|
$result = $condition->GetConditions($count);
|
||||||
|
|
||||||
|
// -- добавляем условие в массив частей
|
||||||
|
$parts[] = $result->Get(0);
|
||||||
|
|
||||||
|
// -- добавляем параметры для защиты от SQL-инъекций в массив
|
||||||
|
$params = array_merge($params, $result->Get(1));
|
||||||
|
|
||||||
|
// -- увеличиваем счётчик
|
||||||
|
$count = $count + count($result->Get(1));
|
||||||
|
|
||||||
|
// -- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если это условие
|
||||||
|
if ($condition instanceof Condition) {
|
||||||
|
// -- парсим его
|
||||||
|
$result = $condition->Get($count);
|
||||||
|
|
||||||
|
// -- добавляем условие в массив частей
|
||||||
|
$parts[] = $result->Get(0);
|
||||||
|
|
||||||
|
// -- добавляем параметры для защиты от SQL-инъекций в массив
|
||||||
|
$params = array_merge($params, $result->Get(1));
|
||||||
|
|
||||||
|
// -- увеличиваем счётчик на 1
|
||||||
|
$count++;
|
||||||
|
|
||||||
|
// -- идём к следующему элементу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// - иначе считаем, что это логический оператор, проверим это
|
||||||
|
$condition = self::PrepareLogicalOperator($condition);
|
||||||
|
|
||||||
|
// - если это не логический оператор
|
||||||
|
if ($condition === false)
|
||||||
|
// -- то пропускаем его
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - добавляем его в массив частей
|
||||||
|
$parts[] = $condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return new Tuple(implode(' ', $parts), $params);
|
||||||
|
}
|
||||||
|
}
|
205
sources/classes/ConditionGroup.php
Normal file
205
sources/classes/ConditionGroup.php
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noinspection SqlNoDataSourceInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\classes;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\classes\Tuple;
|
||||||
|
use goodboyalex\php_components_pack\interfaces\IArrayable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Группа условий запроса выборки по условию.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class ConditionGroup implements IArrayable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string $LogicOperator Логический оператор.
|
||||||
|
*/
|
||||||
|
private string $LogicOperator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array $Conditions Условия.
|
||||||
|
*/
|
||||||
|
private array $Conditions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор.
|
||||||
|
*
|
||||||
|
* @param string $logicOperator Логический оператор.
|
||||||
|
* @param array $conditions Условия.
|
||||||
|
*/
|
||||||
|
public function __construct (string $logicOperator = Condition::LOGIC_AND, array $conditions = [])
|
||||||
|
{
|
||||||
|
$this->LogicOperator = $logicOperator;
|
||||||
|
$this->Conditions = $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Формирует массив условий.
|
||||||
|
*
|
||||||
|
* @param int $index Индекс замены параметров для защиты от SQL-инъекций.
|
||||||
|
*
|
||||||
|
* @return Tuple (string, array) Массив условий (строка SQL, параметры SQL).
|
||||||
|
*/
|
||||||
|
public function GetConditions (int $index = 0): Tuple
|
||||||
|
{
|
||||||
|
// Создаём результирующую строку
|
||||||
|
$resultString = "";
|
||||||
|
|
||||||
|
// Создаём результирующий массив
|
||||||
|
$resultArray = [];
|
||||||
|
|
||||||
|
// Создаём счётчик
|
||||||
|
$count = $index;
|
||||||
|
|
||||||
|
// Проходим по всем элементам, кроме последнего
|
||||||
|
for ($i = 0; $i < count($this->Conditions) - 1; $i++) {
|
||||||
|
// - увеличиваем счётчик
|
||||||
|
$count++;
|
||||||
|
|
||||||
|
// - получаем условие
|
||||||
|
$result = $this->WriteCondition($this->Conditions[$i], $count);
|
||||||
|
|
||||||
|
// - записываем условие в строку
|
||||||
|
$resultString .= $result->Get(0);
|
||||||
|
|
||||||
|
// - записываем условие в массив
|
||||||
|
$resultArray[] = array_merge($resultArray, $result->Get(1));
|
||||||
|
|
||||||
|
// - записываем логический оператор
|
||||||
|
$resultString .= " $this->LogicOperator ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Увеличиваем счётчик
|
||||||
|
$count++;
|
||||||
|
|
||||||
|
// Получаем последнее условие
|
||||||
|
$result = $this->WriteCondition($this->Conditions[count($this->Conditions) - 1], $count);
|
||||||
|
|
||||||
|
// Записываем условие в строку
|
||||||
|
$resultString .= $result->Get(0);
|
||||||
|
|
||||||
|
// Записываем условие в массив
|
||||||
|
$resultArray[] = array_merge($resultArray, $result->Get(1));
|
||||||
|
|
||||||
|
// Очищаем результирующую строку от лишних пробелов
|
||||||
|
$resultString = '(' . trim($resultString) . ')';
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return new Tuple($resultString, $resultArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает количество условий в группе.
|
||||||
|
*
|
||||||
|
* @return int Количество условий в группе.
|
||||||
|
*/
|
||||||
|
public function Count (): int
|
||||||
|
{
|
||||||
|
// Создаём счетчик
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
// Проходим по всем элементам
|
||||||
|
foreach ($this->Conditions as $condition) {
|
||||||
|
// - если это условие
|
||||||
|
if ($condition instanceof Condition)
|
||||||
|
// -- то увеличиваем счетчик
|
||||||
|
$count++;
|
||||||
|
|
||||||
|
// - если это группа условий
|
||||||
|
if ($condition instanceof ConditionGroup)
|
||||||
|
// -- то считаем количество условий в группе и увеличиваем счетчик на это число
|
||||||
|
$count += $condition->Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function ToArray (): array
|
||||||
|
{
|
||||||
|
// Создаём результирующий массив
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Записываем тип класса
|
||||||
|
$result["type_class"] = ConditionGroup::class;
|
||||||
|
|
||||||
|
// Записываем логический оператор
|
||||||
|
$result["LogicOperator"] = $this->LogicOperator;
|
||||||
|
|
||||||
|
// Перебираем все условия
|
||||||
|
foreach ($this->Conditions as $condition)
|
||||||
|
// - записываем условие в массив
|
||||||
|
$result["Conditions"][] = $condition->ToArray();
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function FromArray (array $array): void
|
||||||
|
{
|
||||||
|
// Проверяем, существует ли поле LogicOperator
|
||||||
|
if (isset($array["LogicOperator"]))
|
||||||
|
// - если да, то записываем его значение
|
||||||
|
$this->LogicOperator = $array["LogicOperator"];
|
||||||
|
|
||||||
|
// Проверяем, существует ли поле Conditions
|
||||||
|
if (isset($array["Conditions"]))
|
||||||
|
/**
|
||||||
|
* -- если да, то проходим по всем элементам массива
|
||||||
|
*
|
||||||
|
* @var IArrayable $condition
|
||||||
|
*/
|
||||||
|
foreach ($array["Conditions"] as $condition) {
|
||||||
|
// -- получаем класс по имени
|
||||||
|
$className = $condition["type_class"];
|
||||||
|
|
||||||
|
// -- создаём объект класса
|
||||||
|
$class = new $className();
|
||||||
|
|
||||||
|
// -- заполняем объект
|
||||||
|
$class->FromArray($condition);
|
||||||
|
|
||||||
|
// -- добавляем объект в массив
|
||||||
|
$this->Conditions[] = $class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Формирует условие.
|
||||||
|
*
|
||||||
|
* @param mixed $condition Условие.
|
||||||
|
* @param int $index Индекс замены параметров для защиты от SQL-инъекций.
|
||||||
|
*
|
||||||
|
* @return string Возвращает условие в виде строки SQL.
|
||||||
|
*/
|
||||||
|
private function WriteCondition (mixed $condition, int $index = 0): Tuple
|
||||||
|
{
|
||||||
|
// Проверяем, является ли условие объектом класса Condition
|
||||||
|
if ($condition instanceof Condition)
|
||||||
|
// - если да, то возвращаем его значение
|
||||||
|
return $condition->Get($index);
|
||||||
|
|
||||||
|
// Проверяем, является ли условие объектом класса ConditionGroup
|
||||||
|
if ($condition instanceof ConditionGroup)
|
||||||
|
// - если да, то возвращаем его значения
|
||||||
|
return $condition->GetConditions($index);
|
||||||
|
|
||||||
|
// Если условие не является ни классом Condition, ни классом ConditionGroup, то это ошибка. Выбрасываем
|
||||||
|
// исключение.
|
||||||
|
throw new InvalidArgumentException("Неверное условие / Invalid condition");
|
||||||
|
}
|
||||||
|
}
|
@@ -9,6 +9,7 @@
|
|||||||
use Closure;
|
use Closure;
|
||||||
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||||
use goodboyalex\php_db_components_pack\models\DBConfig;
|
use goodboyalex\php_db_components_pack\models\DBConfig;
|
||||||
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseGet;
|
||||||
use goodboyalex\php_db_components_pack\traits\Database\DatabaseInsert;
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseInsert;
|
||||||
use goodboyalex\php_db_components_pack\traits\Database\DatabaseQueryExecute;
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseQueryExecute;
|
||||||
use goodboyalex\php_db_components_pack\traits\Database\DatabaseSpecial;
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseSpecial;
|
||||||
@@ -168,35 +169,13 @@
|
|||||||
// Вставка данных
|
// Вставка данных
|
||||||
use DatabaseInsert;
|
use DatabaseInsert;
|
||||||
|
|
||||||
|
// Получение данных
|
||||||
|
use DatabaseGet;
|
||||||
|
|
||||||
// Приватные методы
|
// Приватные методы
|
||||||
use DatabaseSpecial;
|
use DatabaseSpecial;
|
||||||
|
|
||||||
/**
|
|
||||||
* Получает первую строку в массиве данных, удовлетворяющую выборке
|
|
||||||
*
|
|
||||||
* @param string $table Имя таблицы
|
|
||||||
* @param array $columns Колонки, которые нужно включить в запрос
|
|
||||||
* @param array $where Параметры выборки
|
|
||||||
*
|
|
||||||
* @return false|array Строка в формате массива или false в случае ошибки
|
|
||||||
*
|
|
||||||
* @see Query
|
|
||||||
* @see QueryFirst
|
|
||||||
* @see QueryLast
|
|
||||||
* @see QueryScalar
|
|
||||||
* @see GetRows
|
|
||||||
*/
|
|
||||||
public function GetRow (string $table, array $columns = [], array $where = []): false|array
|
|
||||||
{
|
|
||||||
// Задаю массив параметров
|
|
||||||
$params = [];
|
|
||||||
|
|
||||||
// Получаю SQL запрос
|
|
||||||
$sql = $this->PrepareSQLForRowsQuery($table, $columns, $where, $params);
|
|
||||||
|
|
||||||
// Получаю строку на основании запроса
|
|
||||||
return $this->QueryScalar($sql, $params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получает колонку в массиве данных
|
* Получает колонку в массиве данных
|
||||||
|
@@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\traits\ConditionBuilder;
|
||||||
|
|
||||||
|
use goodboyalex\php_db_components_pack\classes\Condition;
|
||||||
|
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для построителя условий запроса выборки, отвечающий за задание цепочки условий.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
trait ConditionBuilderConditionsSet
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Добавляет условие равенства.
|
||||||
|
*
|
||||||
|
* @param string $column Имя колонки.
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function WhereEquals (string $column, mixed $value): ConditionBuilder
|
||||||
|
{
|
||||||
|
return $this->AddCondition($column, '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет условие не равенства.
|
||||||
|
*
|
||||||
|
* @param string $column Имя колонки.
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function WhereNotEquals (string $column, mixed $value): ConditionBuilder
|
||||||
|
{
|
||||||
|
return $this->AddCondition($column, '<>', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет условие больше.
|
||||||
|
*
|
||||||
|
* @param string $column Имя колонки.
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function WhereGreaterThan (string $column, mixed $value): ConditionBuilder
|
||||||
|
{
|
||||||
|
return $this->AddCondition($column, '>', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет условие меньше.
|
||||||
|
*
|
||||||
|
* @param string $column Имя колонки.
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function WhereLessThan (string $column, mixed $value): ConditionBuilder
|
||||||
|
{
|
||||||
|
return $this->AddCondition($column, '<', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет условие больше или равно.
|
||||||
|
*
|
||||||
|
* @param string $column Имя колонки.
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function WhereGreaterThanEqual (string $column, mixed $value): ConditionBuilder
|
||||||
|
{
|
||||||
|
return $this->AddCondition($column, '>=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет условие меньше или равно.
|
||||||
|
*
|
||||||
|
* @param string $column Имя колонки.
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function WhereLessThanEqual (string $column, mixed $value): ConditionBuilder
|
||||||
|
{
|
||||||
|
return $this->AddCondition($column, '<=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет условие.
|
||||||
|
*
|
||||||
|
* @param string $column Имя колонки.
|
||||||
|
* @param string $operator Оператор (<=, <, =, >, >=).
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
private function AddCondition (string $column, string $operator, mixed $value): ConditionBuilder
|
||||||
|
{
|
||||||
|
return $this->AddConditionA(new Condition($column, $operator, $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет условие.
|
||||||
|
*
|
||||||
|
* @param Condition $condition Условие.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
private function AddConditionA (Condition $condition): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = $condition;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\traits\ConditionBuilder;
|
||||||
|
|
||||||
|
use goodboyalex\php_db_components_pack\classes\Condition;
|
||||||
|
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для построителя условий запроса выборки, отвечающий за задание логических операторов в цепочку условий.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
trait ConditionBuilderLogicalOperationSet
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Добавляет логический оператор.
|
||||||
|
*
|
||||||
|
* @param string $operator Оператор.
|
||||||
|
*
|
||||||
|
* @return false|ConditionBuilder Возвращает объект для цепочек или <code>false</code>, если оператор не верный.
|
||||||
|
*/
|
||||||
|
public function AddLogicalOperator (string $operator): false|ConditionBuilder
|
||||||
|
{
|
||||||
|
// Подготавливаем оператор
|
||||||
|
$operator = self::PrepareLogicalOperator($operator);
|
||||||
|
|
||||||
|
// Проверяем оператор, и если он не верный
|
||||||
|
if ($operator === false)
|
||||||
|
// - то возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = $operator;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет логическое И.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function And (): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = Condition::LOGIC_AND;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет логическое ИЛИ.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function Or (): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = Condition::LOGIC_OR;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет логическое НЕ.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function Not (): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = Condition::LOGIC_NOT;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет логическое ИСКЛЮЧАЮЩЕЕ ИЛИ.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function Xor (): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = Condition::LOGIC_XOR;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет логическое НЕ И.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function Nand (): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = Condition::LOGIC_NAND;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет логическое НЕ ИЛИ.
|
||||||
|
*
|
||||||
|
* @return ConditionBuilder Возвращает объект для цепочек.
|
||||||
|
*/
|
||||||
|
public function Nor (): ConditionBuilder
|
||||||
|
{
|
||||||
|
// Добавляем условие
|
||||||
|
$this->Conditions[] = Condition::LOGIC_NOR;
|
||||||
|
|
||||||
|
// Возвращаем объект
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
121
sources/traits/Database/DatabaseGet.php
Normal file
121
sources/traits/Database/DatabaseGet.php
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noinspection SqlNoDataSourceInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\traits\Database;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для работы с получением данных из базы данных.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
* @see PDO
|
||||||
|
*/
|
||||||
|
trait DatabaseGet
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Получает первую строку в массиве данных, удовлетворяющую выборке
|
||||||
|
*
|
||||||
|
* @param string $table Имя таблицы
|
||||||
|
* @param array $columns Колонки, которые нужно включить в запрос
|
||||||
|
* @param ConditionBuilder $where Параметры выборки
|
||||||
|
*
|
||||||
|
* @return false|array Строка в формате массива или false в случае ошибки
|
||||||
|
*
|
||||||
|
* @see Query
|
||||||
|
* @see QueryFirst
|
||||||
|
* @see QueryLast
|
||||||
|
* @see QueryScalar
|
||||||
|
* @see GetRows
|
||||||
|
*/
|
||||||
|
public function GetRowColumns (string $table, array $columns, ConditionBuilder $where): false|array
|
||||||
|
{
|
||||||
|
// Задаю массив параметров
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
// Получаю SQL запрос
|
||||||
|
$sql = $this->PrepareSQLForRowsQuery($table, $columns, $where, $params);
|
||||||
|
|
||||||
|
// Получаю строку на основании запроса
|
||||||
|
return $this->QueryScalar($sql, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Извлекает одну запись из базы данных и создает соответствующий объект класса
|
||||||
|
*
|
||||||
|
* @param string $table Название таблицы
|
||||||
|
* @param ConditionBuilder $condition Условия выборки
|
||||||
|
* @param string $className Полное имя класса, реализуемого интерфейсом IDBItem
|
||||||
|
*
|
||||||
|
* @return object Заполненный объект класса
|
||||||
|
*/
|
||||||
|
public function GetRow (string $table, ConditionBuilder $condition, string $className): object
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Строим условие WHERE для SQL-запроса
|
||||||
|
$whereClause = $condition->Build();
|
||||||
|
|
||||||
|
// Формируем SQL-запрос
|
||||||
|
$sql = "SELECT * FROM $table WHERE $whereClause LIMIT 1;";
|
||||||
|
|
||||||
|
// Подготовленное выражение
|
||||||
|
$stmt = $this->pdo->prepare($sql);
|
||||||
|
|
||||||
|
// Присваивание параметров
|
||||||
|
foreach ($params as $col => $val) {
|
||||||
|
$stmt->bindParam(":$col", $val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Выполнение запроса
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
// Получаем первую строку результатов
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
throw new Exception("No data found with the given conditions.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создание объекта желаемого класса
|
||||||
|
$obj = new $className();
|
||||||
|
|
||||||
|
// Заполняем поля объекта соответствующими значениями из БД
|
||||||
|
foreach ($row as $column => $value) {
|
||||||
|
// Анализируем свойства класса и находим соответствующее свойство
|
||||||
|
$properties = (new ReflectionClass($obj))->getProperties(ReflectionProperty::IS_PUBLIC);
|
||||||
|
foreach ($properties as $prop) {
|
||||||
|
// Проверяем, соответствует ли данное свойство указанному полю
|
||||||
|
$attributes = $prop->getAttributes(FieldName::class);
|
||||||
|
if ($attributes && $attributes[0]->getArguments()['name'] === $column) {
|
||||||
|
// Применяем процедуру конвертации (если указана)
|
||||||
|
$convertAttrs = $prop->getAttributes(ConvertToDB::class);
|
||||||
|
if ($convertAttrs) {
|
||||||
|
$converter = $convertAttrs[0]->getArguments()['fromDb'];
|
||||||
|
if ($converter !== null) {
|
||||||
|
$value = call_user_func($converter, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Устанавливаем значение свойства
|
||||||
|
$obj->{$prop->getName()} = $value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
catch (\PDOException|\Exception $e) {
|
||||||
|
error_log("Error fetching data: " . $e->getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use goodboyalex\php_components_pack\classes\Tuple;
|
use goodboyalex\php_components_pack\classes\Tuple;
|
||||||
|
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||||
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
||||||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||||
use PDO;
|
use PDO;
|
||||||
use PDOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Трейт для работы со вставкой строк в базу данных.
|
* Трейт для работы со вставкой строк в базу данных.
|
||||||
@@ -46,23 +46,17 @@
|
|||||||
// - то и общий результат - false
|
// - то и общий результат - false
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
$lastId = -1;
|
// Задаю переменную для последнего id
|
||||||
|
$lastId = match ($this->Config->Driver) {
|
||||||
|
DBDriver::MSSQL => $this->DataBaseHandle->query('SELECT SCOPE_IDENTITY()')->fetchColumn(),
|
||||||
|
DBDriver::MySQL, DBDriver::SQLite => $this->DataBaseHandle->lastInsertId(),
|
||||||
|
DBDriver::PostgreSQL, DBDriver::OracleDB => $this->DataBaseHandle->lastInsertId('sequence_name')
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
// Если id не получен
|
||||||
// Получаю последний id этой записи
|
if ($lastId === false)
|
||||||
$lastIdResult = $this->DataBaseHandle->lastInsertId();
|
// - то вывожу просто true
|
||||||
|
$lastId = true;
|
||||||
// Если получение неудачное
|
|
||||||
if ($lastIdResult === false)
|
|
||||||
// - то вывожу -1
|
|
||||||
return $lastId;
|
|
||||||
|
|
||||||
// Устанавливаю последний id
|
|
||||||
$lastId = $lastIdResult;
|
|
||||||
}
|
|
||||||
catch (PDOException $e) {
|
|
||||||
$this->HandleException($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Вывожу последний id
|
// Вывожу последний id
|
||||||
return $lastId;
|
return $lastId;
|
||||||
@@ -72,33 +66,38 @@
|
|||||||
* Вставляет несколько строк в базу данных.
|
* Вставляет несколько строк в базу данных.
|
||||||
*
|
*
|
||||||
* @param string $table Имя таблицы.
|
* @param string $table Имя таблицы.
|
||||||
* @param array $options Параметры.
|
|
||||||
* @param IDBItem ...$sources Модели или классы, реализующие интерфейс IDBItem, для вставки.
|
* @param IDBItem ...$sources Модели или классы, реализующие интерфейс IDBItem, для вставки.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return false|array Возвращает массив id созданных записей и <code>false</code>, если ошибка.
|
||||||
*/
|
*/
|
||||||
public function InsertMany (string $table, array $options, IDBItem ...$sources): void
|
public function InsertMany (string $table, IDBItem ...$sources): false|array
|
||||||
{
|
{
|
||||||
// Инициализирую транзакцию
|
// Инициализирую транзакцию
|
||||||
$this->InitTransaction();
|
$this->InitTransaction();
|
||||||
|
|
||||||
|
// Подготавливаю массив последних id
|
||||||
|
$result = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Для каждого источника
|
// Для каждого источника
|
||||||
foreach ($sources as $source)
|
foreach ($sources as $source)
|
||||||
// - вставляю строку
|
// - вставляю строку
|
||||||
$this->Insert($table, $source, $options);
|
$result[] = $this->Insert($table, $source);
|
||||||
|
|
||||||
// Если вставка успешна, то подтверждаю транзакцию
|
// Если вставка успешна, то подтверждаю транзакцию
|
||||||
$this->Commit();
|
$this->Commit();
|
||||||
}
|
}
|
||||||
catch (Exception $exception) {
|
catch (Exception) {
|
||||||
// - если ошибка, то откатываю транзакцию
|
// - если ошибка, то откатываю транзакцию
|
||||||
$this->RollBack();
|
$this->RollBack();
|
||||||
|
|
||||||
// - и вывожу ошибку
|
// - и вывожу ошибку
|
||||||
$this->HandleException($exception);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Вывожу результат
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,7 +105,6 @@
|
|||||||
*
|
*
|
||||||
* @param string $table Имя таблицы.
|
* @param string $table Имя таблицы.
|
||||||
* @param IDBItem $row Элемент.
|
* @param IDBItem $row Элемент.
|
||||||
* @param array $options Параметры.
|
|
||||||
*
|
*
|
||||||
* @return Tuple Возвращает [запрос, параметры запроса].
|
* @return Tuple Возвращает [запрос, параметры запроса].
|
||||||
*/
|
*/
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
use goodboyalex\php_db_components_pack\attributes\ConvertToDB;
|
use goodboyalex\php_db_components_pack\attributes\ConvertToDB;
|
||||||
use goodboyalex\php_db_components_pack\attributes\FieldName;
|
use goodboyalex\php_db_components_pack\attributes\FieldName;
|
||||||
use goodboyalex\php_db_components_pack\attributes\IgnoredInDB;
|
use goodboyalex\php_db_components_pack\attributes\IgnoredInDB;
|
||||||
|
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||||
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
||||||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||||
use PDO;
|
use PDO;
|
||||||
@@ -235,7 +236,7 @@
|
|||||||
*
|
*
|
||||||
* @return string SQL-запрос
|
* @return string SQL-запрос
|
||||||
*/
|
*/
|
||||||
private function PrepareSQLForRowsQuery (string $table, array $columns = [], array $where = [],
|
private function PrepareSQLForRowsQuery (string $table, array $columns, ConditionBuilder $where,
|
||||||
array &$params = []): string
|
array &$params = []): string
|
||||||
{
|
{
|
||||||
// Очищаю параметры
|
// Очищаю параметры
|
||||||
|
48
tests/classes/ConditionBuilderTest.php
Normal file
48
tests/classes/ConditionBuilderTest.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\tests\classes;
|
||||||
|
|
||||||
|
use goodboyalex\php_db_components_pack\classes\Condition;
|
||||||
|
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||||
|
use goodboyalex\php_db_components_pack\classes\ConditionGroup;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ConditionBuilderTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testBuild ()
|
||||||
|
{
|
||||||
|
// Требуемое условие
|
||||||
|
$requireCondition =
|
||||||
|
"`id` = 1 AND `age` >= 18 OR `profile` <= 12 AND (`Name` = 'Alex' AND (`Age` > 18 OR `FirstName` = 'Titanic'))";
|
||||||
|
|
||||||
|
// Создаем условие методом цепочек
|
||||||
|
$condition = new ConditionBuilder()->WhereEquals('id', 1)->And()->WhereGreaterThanEqual('age', 18)->Or()
|
||||||
|
->WhereLessThanEqual('profile', 12)->And()->AddGroup(Condition::LOGIC_AND, [
|
||||||
|
new Condition("Name", '=', "Alex"),
|
||||||
|
new ConditionGroup(Condition::LOGIC_OR, [
|
||||||
|
new Condition("Age", '>', 18), new Condition("FirstName",
|
||||||
|
'=',
|
||||||
|
"Titanic")
|
||||||
|
]),
|
||||||
|
])->Build();
|
||||||
|
|
||||||
|
var_dump($condition->Get(0));
|
||||||
|
var_dump($condition->Get(1));
|
||||||
|
|
||||||
|
// Проверяем его
|
||||||
|
$this->assertEquals($requireCondition, $condition);
|
||||||
|
|
||||||
|
// Задаем условие методом массива
|
||||||
|
$conditionArray = [
|
||||||
|
"id" => 1, 'AND', "age" => ['>=', 18], 'OR', "profile" => ['<=', 12], 'AND', [
|
||||||
|
'AND', "Name" => "Alex", ['OR', "Age" => ['>', 18], "FirstName" => "Titanic"]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
// Создаем ConditionBuilder
|
||||||
|
$builder = ConditionBuilder::Parse($conditionArray);
|
||||||
|
|
||||||
|
// Проверяем его
|
||||||
|
$this->assertEquals($requireCondition, $builder->Build());
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user