20250820 v1.0.2-b2
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2233,4 +2233,4 @@ FodyWeavers.xsd
|
||||
/vendor/phpunit/phpunit/src/Framework/Exception/ErrorLogNotWritableException.php
|
||||
/vendor/phpunit/phpunit/src/Runner/ShutdownHandler.php
|
||||
/.idea/codeStyles/
|
||||
/tests/secret_not_in_git/
|
||||
/tests/database_config.php
|
@@ -1,4 +1,4 @@
|
||||
# Пороверка существования данных и их количество
|
||||
# Проверка существования данных и их количество
|
||||
|
||||
Итак, в [прошлой статье](get_data.md) мы получали данные из таблицы `users`. Напомним, что она имеет вид:
|
||||
|
||||
|
@@ -12,7 +12,7 @@ namespace goodboyalex\php_db_components_pack;
|
||||
## Автор и версия
|
||||
|
||||
- **Автор**: Александр Бабаев
|
||||
- **Версия**: 1.0
|
||||
- **Версия**: 1.0.2
|
||||
- **Дата начала поддержки**: с версии 1.0
|
||||
|
||||
## Назначение
|
||||
@@ -82,8 +82,10 @@ $condition = new Condition('FUNC:SUBSTR(name, 1, 1)', "=", 'FUNC:UPPER(SUBSTR(na
|
||||
```
|
||||
|
||||
в результате запрос будет содержать:
|
||||
|
||||
```sql
|
||||
SUBSTR(name, 1, 1) = UPPER(SUBSTR(name, 1, 1)
|
||||
SUBSTR
|
||||
(name, 1, 1) = UPPER(SUBSTR(name, 1, 1)
|
||||
```
|
||||
|
||||
### 2. Метод `Parse`
|
||||
@@ -114,11 +116,12 @@ $parsedCondition = Condition::Parse(['age', '>', 18]);
|
||||
**Синтаксис**:
|
||||
|
||||
```php
|
||||
public function Get(int $index = 0): Tuple;
|
||||
public function Get(DBDriver $driver, int $index = 0): Tuple;
|
||||
```
|
||||
|
||||
**Описание**:
|
||||
|
||||
- **$driver**: Тип драйвера СУБД.
|
||||
- **$index**: Индексация для замены переменных (для предотвращения SQL-инъекций).
|
||||
- Метод возвращает кортеж (tuple), состоящий из двух частей:
|
||||
- SQL-строку с замещаемым параметром (`:paramX`), где X — номер индекса.
|
||||
@@ -127,7 +130,7 @@ public function Get(int $index = 0): Tuple;
|
||||
**Пример использования**:
|
||||
|
||||
```php
|
||||
[$sqlPart, $params] = $condition->Get();
|
||||
[$sqlPart, $params] = $condition->Get(\goodboyalex\php_db_components_pack\enums\DBDriver::MySQL);
|
||||
// $sqlPart будет выглядеть примерно так: "`age` > :param0"
|
||||
// $params будет содержать массив с фактическим значением: ["param0" => 18]
|
||||
```
|
||||
@@ -136,12 +139,13 @@ public function Get(int $index = 0): Tuple;
|
||||
|
||||
```php
|
||||
use goodboyalex\php_db_components_pack\Condition;
|
||||
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||
|
||||
// Создаём условие для поиска пользователей по возрасту
|
||||
$condition = new Condition('age', '>', 18);
|
||||
|
||||
// Формируем условие для использования в SQL-запросе
|
||||
list($sql, $parameters) = $condition->Get();
|
||||
[$sql, $parameters] = $condition->Get(DBDriver::MySQL);
|
||||
|
||||
// Теперь можем использовать $sql и $parameters в запросе
|
||||
$query = "SELECT * FROM users WHERE $sql";
|
||||
|
@@ -13,7 +13,7 @@ namespace goodboyalex\php_db_components_pack\classes;
|
||||
## Автор и версия
|
||||
|
||||
- **Автор**: Александр Бабаев
|
||||
- **Версия**: 1.0
|
||||
- **Версия**: 1.0.2
|
||||
- **Дата начала поддержки**: с версии 1.0
|
||||
|
||||
## Назначение
|
||||
@@ -125,11 +125,12 @@ $builder = new ConditionBuilder()->AddGroup(Condition::LOGIC_OR, [new Condition(
|
||||
**Синтаксис**:
|
||||
|
||||
```php
|
||||
public function Build(): Tuple;
|
||||
public function Build(DBDriver $driver): Tuple;
|
||||
```
|
||||
|
||||
**Описание**:
|
||||
|
||||
- **$driver**: Тип драйвера СУБД.
|
||||
- Метод возвращает кортеж (Tuple), состоящий из двух элементов:
|
||||
- SQL-строка с условием, готовым к выполнению.
|
||||
- Массив параметров, необходимых для последующей передачи в подготовленный SQL-запрос.
|
||||
@@ -139,7 +140,7 @@ public function Build(): Tuple;
|
||||
|
||||
```php
|
||||
// $sql будет (`age` >= :age), а params - [':age' = 18]
|
||||
[$sql, $params] = new ConditionBuilder()->AddCondition('age', '>=', 18)->Build();
|
||||
[$sql, $params] = new ConditionBuilder()->AddCondition('age', '>=', 18)->Build(\goodboyalex\php_db_components_pack\enums\DBDriver::MySQL);
|
||||
```
|
||||
|
||||
---
|
||||
@@ -317,9 +318,11 @@ public function WhereLike(string $column, string $value): ConditionBuilder;
|
||||
```
|
||||
|
||||
**Описание**:
|
||||
|
||||
- **$column**: Имя колонки, по которой проводится поиск.
|
||||
- **$value**: Шаблон для поиска (обычно включает символы `%` для указания маски).
|
||||
- Метод добавляет условие в виде `WHERE column LIKE '%value%'` и возвращает объект для продолжительного построения условий.
|
||||
- Метод добавляет условие в виде `WHERE column LIKE '%value%'` и возвращает объект для продолжительного построения
|
||||
условий.
|
||||
|
||||
**Пример использования**:
|
||||
|
||||
@@ -341,10 +344,12 @@ public function AddCondition(string $column, string $operator, mixed $value): Co
|
||||
```
|
||||
|
||||
**Описание**:
|
||||
|
||||
- **$column**: Имя колонки, участвующей в условии.
|
||||
- **$operator**: Любой оператор сравнения (например, `=`, `!=`, `<`, `>`, `IN`, `BETWEEN`, и т.д.).
|
||||
- **$value**: Значение, с которым производится сравнение.
|
||||
- Метод добавляет условие в форме `WHERE column OPERATOR value` и возвращает объект для продолжения построения цепочки условий.
|
||||
- Метод добавляет условие в форме `WHERE column OPERATOR value` и возвращает объект для продолжения построения цепочки
|
||||
условий.
|
||||
|
||||
**Пример использования**:
|
||||
|
||||
|
@@ -13,7 +13,7 @@ namespace goodboyalex\php_db_components_pack\classes;
|
||||
## Автор и версия
|
||||
|
||||
- **Автор**: Александр Бабаев
|
||||
- **Версия**: 1.0
|
||||
- **Версия**: 1.0.2
|
||||
- **Дата начала поддержки**: с версии 1.0
|
||||
|
||||
## Назначение
|
||||
|
@@ -6,7 +6,7 @@
|
||||
## Основная информация
|
||||
|
||||
- **Автор**: Александр Бабаев
|
||||
- **Версия**: 1.0
|
||||
- **Версия**: 1.0.2
|
||||
- **Дата начала поддержки**: с версии 1.0
|
||||
|
||||
## Пространство имен и зависимости
|
||||
@@ -27,6 +27,64 @@ use goodboyalex\php_components_pack\traits\EnumExtensionsTrait;
|
||||
| `OracleDB` | `3` | Драйвер Oracle |
|
||||
| `SQLite` | `4` | Драйвер SQLite |
|
||||
|
||||
## Методы
|
||||
|
||||
### Метод `GetSigns`
|
||||
|
||||
Метод `GetSigns` предназначен для получения знаков, которыми принято заключать имена полей и таблиц в различных системах
|
||||
управления базами данных (СУБД). Некоторые СУБД используют двойные кавычки `"`, квадратные скобки `[]`, обратные
|
||||
апострофы `` ` `` или другие специальные символы для экранирования идентификаторов (имен таблиц, колонок и других
|
||||
объектов базы данных).
|
||||
|
||||
#### Синтаксис
|
||||
|
||||
```php
|
||||
public static function GetSigns(DBDriver $driver): Tuple
|
||||
```
|
||||
|
||||
#### Аргументы
|
||||
|
||||
- **$driver**: Переменная типа `DBDriver`, указывающая на используемую СУБД (например, MySQL, PostgreSQL, SQLite и
|
||||
т.д.).
|
||||
|
||||
#### Возвращаемое значение
|
||||
|
||||
Метод возвращает кортеж `Tuple`, содержащий два элемента:
|
||||
|
||||
- Первый элемент — знак открывающий.
|
||||
- Второй элемент — знак закрывающий.
|
||||
|
||||
Например, для `MySQL` и `PostgreSQL` чаще всего возвращаются символы обратной косой черты и прямой (```"``, ```"``)
|
||||
соответственно, а для `MS SQL Server` — квадратные скобки (`[`, `]`).
|
||||
|
||||
#### Пример использования
|
||||
|
||||
Допустим, у вас есть код, который выводит SQL-запрос с экранированием идентификатора в зависимости от используемой СУБД:
|
||||
|
||||
```php
|
||||
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||
|
||||
// Получаем знаки для MySQL
|
||||
[$open, $close] = DBDriver::GetSigns(DBDriver::MYSQL);
|
||||
|
||||
// Использование полученных знаков
|
||||
$sql = sprintf("SELECT %s%s%s FROM users;", $open, 'username', $close);
|
||||
```
|
||||
|
||||
В результате для MySQL получится:
|
||||
|
||||
```sql
|
||||
SELECT `username`
|
||||
FROM users;
|
||||
```
|
||||
|
||||
Аналогично, для PostgreSQL:
|
||||
|
||||
```sql
|
||||
SELECT "username"
|
||||
FROM users;
|
||||
```
|
||||
|
||||
## Особенности реализации
|
||||
|
||||
Используется trait `EnumExtensionsTrait`, предоставляющий дополнительные методы для работы с перечислениями, такие как
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Добро пожаловать в справочное руководство по компонентам PHP DB COMPONENTS PACK!
|
||||
|
||||
**Руководство актуально для версии v1.0**
|
||||
**Руководство актуально для версии v1.0.2**
|
||||
|
||||
**Автор: Александр Бабаев**
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
2. [x] [Создание таблицы](basic_usage/create_table.md)
|
||||
3. [x] [Вставка данных](basic_usage/insert_data.md)
|
||||
4. [x] [Получение данных](basic_usage/get_data.md)
|
||||
5. [x] [Пороверка существования данных и их количество](basic_usage/count_exist_data.md)
|
||||
5. [x] [Проверка существования данных и их количество](basic_usage/count_exist_data.md)
|
||||
6. [x] [Обновление данных](basic_usage/update_data.md)
|
||||
7. [x] [Удаление данных](basic_usage/delete_data.md)
|
||||
8. [x] [Удаление таблицы](basic_usage/drop_table.md)
|
||||
|
@@ -13,7 +13,7 @@
|
||||
*
|
||||
* @author Александр Бабаев
|
||||
* @package php_db_components_pack
|
||||
* @version 1.0
|
||||
* @version 1.0.2
|
||||
* @since 1.0
|
||||
*/
|
||||
final class Condition implements IArrayable
|
||||
|
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* @author Александр Бабаев
|
||||
* @package php_components_pack
|
||||
* @version 1.0
|
||||
* @version 1.0.2
|
||||
* @since 1.0
|
||||
*/
|
||||
final class ConditionBuilder implements IArrayable
|
||||
|
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* @author Александр Бабаев
|
||||
* @package php_components_pack
|
||||
* @version 1.0
|
||||
* @version 1.0.2
|
||||
* @since 1.0
|
||||
*/
|
||||
final class ConditionGroup implements IArrayable
|
||||
|
@@ -10,7 +10,7 @@
|
||||
*
|
||||
* @author Александр Бабаев
|
||||
* @package php_db_components_pack
|
||||
* @version 1.0
|
||||
* @version 1.0.2
|
||||
* @since 1.0
|
||||
* @see \PDO
|
||||
*/
|
||||
|
@@ -36,7 +36,7 @@
|
||||
* @var string $sql_where Строка WHERE условий.
|
||||
* @var array $params Параметры условий.
|
||||
*/
|
||||
[$sql_where, $params] = $where->Build();
|
||||
[$sql_where, $params] = $where->Build($this->Config->Driver);
|
||||
|
||||
// Подготавливаю имя таблицы
|
||||
$table = $this->PrepareTableName($table);
|
||||
|
@@ -29,16 +29,19 @@
|
||||
*/
|
||||
public function Delete (string $table, ConditionBuilder $where = new ConditionBuilder()): bool
|
||||
{
|
||||
// Подготавливаю имя таблицы
|
||||
$table = $this->PrepareTableName($table);
|
||||
|
||||
/**
|
||||
* Получаю SQL-запрос и параметры для where.
|
||||
*
|
||||
* @var string $sql_where SQL-запрос для where.
|
||||
* @var array $params Параметры запроса.
|
||||
*/
|
||||
[$sql_where, $params] = $where->Build();
|
||||
[$sql_where, $params] = $where->Build($this->Config->Driver);
|
||||
|
||||
// Создаю запрос
|
||||
$sql = "DELETE FROM $this->DBSignOpen$table$this->DBSignClose";
|
||||
$sql = "DELETE FROM $table";
|
||||
|
||||
// Если заданы where-параметры
|
||||
if ($where->Count() > 0)
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
use goodboyalex\php_components_pack\classes\ObjectArray;
|
||||
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
||||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||
use PDO;
|
||||
@@ -38,17 +39,17 @@
|
||||
// Задаю массив параметров
|
||||
$params = [];
|
||||
|
||||
// Подготавливаю имя таблицы
|
||||
$table = $this->PrepareTableName($table);
|
||||
|
||||
// Формируем SQL-запрос
|
||||
$sql = $this->PrepareSQLForRowsQuery($table, $columns, $where, $params);
|
||||
|
||||
// Добавляю лимит
|
||||
$sql .= " LIMIT 1";
|
||||
|
||||
// Получаю строку
|
||||
$row = $this->Query($sql, $params);
|
||||
$row = $this->QueryFirst($sql, $params);
|
||||
|
||||
// Если не получено
|
||||
if ($row === false)
|
||||
if ($row === false || count($row) == 0)
|
||||
// - то вывожу false
|
||||
return false;
|
||||
|
||||
@@ -80,6 +81,9 @@
|
||||
// Задаю массив параметров
|
||||
$params = [];
|
||||
|
||||
// Подготавливаю имя таблицы
|
||||
$table = $this->PrepareTableName($table);
|
||||
|
||||
// Получаю SQL запрос
|
||||
$sql = $this->PrepareSQLForRowsQuery($table, $columns, $where, $params);
|
||||
|
||||
@@ -124,18 +128,23 @@
|
||||
* @see Query
|
||||
*/
|
||||
public function GetCol (string $table, string $column, ConditionBuilder $where = new ConditionBuilder()):
|
||||
false|array
|
||||
{
|
||||
false | array {
|
||||
/**
|
||||
* Интерпретирую условия.
|
||||
*
|
||||
* @var string $sql_where Строка запроса.
|
||||
* @var array $params Массив параметров строки запроса.
|
||||
*/
|
||||
[$sql_where, $params] = $where->Build();
|
||||
[$sql_where, $params] = $where->Build($this->Config->Driver);
|
||||
|
||||
// Получаю знаки открытия параметра и закрытия его
|
||||
[$signOpen, $signClose] = DBDriver::GetSigns($this->Config->Driver);
|
||||
|
||||
// Подготавливаю имя таблицы
|
||||
$table = $this->PrepareTableName($table);
|
||||
|
||||
// Создаю запрос
|
||||
$sql = "SELECT $this->DBSignOpen$column$this->DBSignClose FROM $this->DBSignOpen$table$this->DBSignClose";
|
||||
$sql = "SELECT $signOpen$column$signClose FROM $table";
|
||||
|
||||
// Если заданы where-параметры
|
||||
if ($where->Count() > 0)
|
||||
|
@@ -119,6 +119,9 @@
|
||||
// Подготавливаю массив параметров
|
||||
$params = [];
|
||||
|
||||
// Получаю знаки открытия параметра и закрытия его
|
||||
[$signOpen, $signClose] = DBDriver::GetSigns($this->Config->Driver);
|
||||
|
||||
// Получаю массив свойств
|
||||
$properties = self::GetProperties($row, DBOperation::Insert);
|
||||
|
||||
@@ -157,7 +160,7 @@
|
||||
$keyReal = $key[0] == ":" ? substr($key, 1) : $key;
|
||||
|
||||
// - добавляю в результирующий массив ключей
|
||||
$keys_params[] = "$this->DBSignOpen$keyReal$this->DBSignClose";
|
||||
$keys_params[] = "$signOpen$keyReal$signClose";
|
||||
|
||||
// - добавляю в результирующий массив значений
|
||||
$keys_values[] = ":$keyReal";
|
||||
|
@@ -291,12 +291,12 @@
|
||||
* @param string $className Имя класса объекта.
|
||||
* @param DBOperation $operation Операция.
|
||||
*
|
||||
* @return object|null Экземпляр класса объекта или <code>null</code>, если ошибка.
|
||||
* @return IDBItem|null Экземпляр класса объекта или <code>null</code>, если ошибка.
|
||||
*/
|
||||
private function RestoreItem (array $row, string $className, DBOperation $operation): ?object
|
||||
private function RestoreItem (array $row, string $className, DBOperation $operation): ?IDBItem
|
||||
{
|
||||
// Если целевой класс не реализует интерфейс IDBItem
|
||||
if (in_array(IDBItem::class, class_implements($className)))
|
||||
if (!is_a($className, IDBItem::class, true))
|
||||
// - то прерываем и возвращаем null
|
||||
return null;
|
||||
|
||||
@@ -385,8 +385,12 @@
|
||||
*/
|
||||
private function PrepareColumn (array $columns): array
|
||||
{
|
||||
// Получаю знаки открытия параметра и закрытия его
|
||||
[$signOpen, $signClose] = DBDriver::GetSigns($this->Config->Driver);
|
||||
|
||||
// Возвращаю результат
|
||||
return array_map(
|
||||
function ($item)
|
||||
function ($item) use ($signOpen, $signClose)
|
||||
{
|
||||
// Результирующая строка
|
||||
$result = "";
|
||||
@@ -399,18 +403,18 @@
|
||||
// - последний символ
|
||||
$lastLetter = substr($item, -1);
|
||||
|
||||
// - если первый символ не $this->DBSignOpen
|
||||
if ($firstLetter !== $this->DBSignOpen)
|
||||
// - если первый символ не $signOpen
|
||||
if ($firstLetter !== $signOpen)
|
||||
// -- то добавляем
|
||||
$result .= $this->DBSignOpen;
|
||||
$result .= $signOpen;
|
||||
|
||||
// - добавляем строку
|
||||
$result .= $item;
|
||||
|
||||
// - если последний символ не $this->DBSignClose
|
||||
if ($lastLetter !== $this->DBSignClose)
|
||||
// - если последний символ не $signClose
|
||||
if ($lastLetter !== $signClose)
|
||||
// -- то добавляем
|
||||
$result .= $this->DBSignClose;
|
||||
$result .= $signClose;
|
||||
}
|
||||
|
||||
// Возвращаем результат
|
||||
@@ -438,13 +442,13 @@
|
||||
* @var string $sql_where where-запрос SQL
|
||||
* @var array $params Параметры и их значения (для защиты от SQL-инъекции)
|
||||
*/
|
||||
[$sql_where, $params] = $whereConditions->Build();
|
||||
[$sql_where, $params] = $whereConditions->Build($this->Config->Driver);
|
||||
|
||||
// Колонки
|
||||
$sql_columns = count($columns) > 0 ? implode(', ', $this->PrepareColumn($columns)) : "*";
|
||||
|
||||
// Создаю запрос
|
||||
$sql = "SELECT $sql_columns FROM $this->DBSignOpen$table$this->DBSignClose";
|
||||
$sql = "SELECT $sql_columns FROM $table";
|
||||
|
||||
// Если заданы where-параметры
|
||||
if ($whereConditions->Count() > 0)
|
||||
@@ -464,9 +468,13 @@
|
||||
*/
|
||||
private function PrepareTableName (string $table): string
|
||||
{
|
||||
// Получаю знаки открытия параметра и закрытия его
|
||||
[$signOpen, $signClose] = DBDriver::GetSigns($this->Config->Driver);
|
||||
|
||||
// Возвращаю результат
|
||||
return match ($this->Config->Driver) {
|
||||
DBDriver::MySQL, DBDriver::SQLite, DBDriver::OracleDB, DBDriver::PostgreSQL => $this->DBSignOpen
|
||||
. $table . $this->DBSignClose,
|
||||
DBDriver::MySQL, DBDriver::SQLite, DBDriver::OracleDB, DBDriver::PostgreSQL =>
|
||||
"$signOpen$table$signClose",
|
||||
DBDriver::MSSQL => "[dbo].[$table]"
|
||||
};
|
||||
}
|
||||
|
@@ -135,8 +135,11 @@
|
||||
// - то возвращаем true
|
||||
return true;
|
||||
|
||||
// Обрабатываю имя таблицы
|
||||
$tableName = $this->PrepareTableName($tableName);
|
||||
|
||||
// SQL-запрос
|
||||
$sql = "DROP TABLE dbo.`$tableName`";
|
||||
$sql = "DROP TABLE $tableName";
|
||||
|
||||
// Инициализирую транзакцию
|
||||
$this->InitTransaction();
|
||||
@@ -169,6 +172,6 @@
|
||||
}
|
||||
|
||||
// Возвращаю, существует ли теперь таблица
|
||||
return $this->IsTableExist($tableName);
|
||||
return !$this->IsTableExist($tableName);
|
||||
}
|
||||
}
|
@@ -7,6 +7,7 @@
|
||||
|
||||
use Exception;
|
||||
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
||||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||
use goodboyalex\php_db_components_pack\models\DBItemProperty;
|
||||
@@ -33,6 +34,9 @@
|
||||
*/
|
||||
public function Update (string $table, IDBItem $item): bool
|
||||
{
|
||||
// Получаю знаки открытия параметра и закрытия его
|
||||
[$signOpen, $signClose] = DBDriver::GetSigns($this->Config->Driver);
|
||||
|
||||
// Получаю свойства объекта
|
||||
$properties = self::GetProperties($item, DBOperation::Update);
|
||||
|
||||
@@ -124,14 +128,19 @@
|
||||
// Для каждого свойства для обновления
|
||||
foreach ($propertyToSet as $key => $value) {
|
||||
// - добавляю его в массив set
|
||||
$set[] = "$this->DBSignOpen$key$this->DBSignClose=:$key";
|
||||
$set[] = "$key=:$key";//"$signOpen$key$signClose=:$key";
|
||||
|
||||
// - добавляю его в массив параметров set для обновления
|
||||
$set_params[":$key"] = $value;
|
||||
}
|
||||
|
||||
// Строковая интерпретация массива set
|
||||
$sql_set = count($set) > 0 ? '(' . implode(", ", $set) . ')' : "";
|
||||
// Если нечего изменять
|
||||
if (count($set) == 0)
|
||||
// - то прерываем с успехом
|
||||
return true;
|
||||
|
||||
// Устанавливаю параметры обновления
|
||||
$sql_set = implode(", ", $set);
|
||||
|
||||
/**
|
||||
* Получаю WHERE-запрос и параметры.
|
||||
@@ -139,13 +148,16 @@
|
||||
* @var string $sql_where WHERE-запрос.
|
||||
* @var array $where_params Параметры WHERE-запроса.
|
||||
*/
|
||||
[$sql_where, $where_params] = $where->Build();
|
||||
[$sql_where, $where_params] = $where->Build($this->Config->Driver);
|
||||
|
||||
// Объединяю все параметры в один массив
|
||||
$params = array_merge($set_params, $where_params);
|
||||
|
||||
// Подготавливаю имя таблицы
|
||||
$table = $this->PrepareTableName($table);
|
||||
|
||||
// Создаю запрос
|
||||
$sql = "UPDATE $this->DBSignOpen$table$this->DBSignClose SET $sql_set";
|
||||
$sql = "UPDATE $table SET $sql_set";
|
||||
|
||||
// Если заданы where-параметры
|
||||
if ($where->Count() > 0)
|
||||
|
408
tests/classes/DatabaseTest.php
Normal file
408
tests/classes/DatabaseTest.php
Normal file
@@ -0,0 +1,408 @@
|
||||
<?php
|
||||
|
||||
namespace goodboyalex\php_db_components_pack\tests\classes;
|
||||
|
||||
use Exception;
|
||||
use goodboyalex\php_components_pack\classes\ObjectArray;
|
||||
use goodboyalex\php_components_pack\types\GUID;
|
||||
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||
use goodboyalex\php_db_components_pack\classes\Database;
|
||||
use goodboyalex\php_db_components_pack\models\DBConfig;
|
||||
use goodboyalex\php_db_components_pack\tests\data\UserModel;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class DatabaseTest extends TestCase
|
||||
{
|
||||
public function testDatabase ()
|
||||
{
|
||||
/**
|
||||
* ВНИМАТЕЛЬНО ПРОЧТИТЕ, ПЕРЕД ВЫПОЛНЕНИЕМ ТЕСТА.
|
||||
*
|
||||
* Подготовка к тесту:
|
||||
*
|
||||
* - создайте тестовую базу данных;
|
||||
* - создайте пользователя и его пароль;
|
||||
* - сделайте его создателем с правами управления созданной в п. 1 БД;
|
||||
* - в корне папки "tests" создайте файл "database_config.php";
|
||||
* - убедитесь, что он добавлен в .gitignore и НИКАКИМ ОБРАЗОМ НЕ ПОПАДЁТ В РЕПОЗИТАРИЙ (это
|
||||
* скомпрометирует вшу БД!);
|
||||
* - в этом файле задайте переменной $testConfig класс настроек с необходимыми настройками или можете
|
||||
* воспользоваться файлом "database_config_sample.php", переименовав его в "database_config.php".
|
||||
*/
|
||||
|
||||
/**
|
||||
* Подключаем настройки базы данных.
|
||||
*
|
||||
* @var DBConfig $testConfig Конфигурация СУБД.
|
||||
*/
|
||||
require_once "../database_config.php";
|
||||
|
||||
// Подключаем данные
|
||||
require_once '../data/Converters.php';
|
||||
require_once '../data/UserModel.php';
|
||||
|
||||
// Задаём действие при ошибке
|
||||
$onException = fn (Exception $exception, bool $terminate)
|
||||
=> $terminate
|
||||
? die($exception->getMessage())
|
||||
: print $exception->getMessage();
|
||||
|
||||
// Подключаем базу данных
|
||||
$db = new Database($testConfig, $onException);
|
||||
|
||||
/* ТЕСТ 1: Создание таблицы */
|
||||
|
||||
// Задаём имя таблицы
|
||||
$tableName = 'users';
|
||||
|
||||
// Создаю таблицу
|
||||
$db->CreateTable(
|
||||
tableName: $tableName,
|
||||
dbItemClass: '\goodboyalex\php_db_components_pack\tests\data\UserModel'
|
||||
);
|
||||
|
||||
// Проверяю создание
|
||||
$this->assertTrue($db->IsTableExist($tableName));
|
||||
|
||||
/* 2. Добавление данных */
|
||||
|
||||
/* 2.1. Модели */
|
||||
|
||||
// Модель 1
|
||||
$model1 = new UserModel(
|
||||
id: GUID::Parse('8b5dab25-4445-436c-8f25-0f5352cb8500', true),
|
||||
login: "account1",
|
||||
password: "password1",
|
||||
salt: GUID_EMPTY,
|
||||
firstName: "firstName1",
|
||||
middleName: "middleName1",
|
||||
lastName: "lastName1",
|
||||
email: "email1@ya.ru",
|
||||
isEmailVerified: false,
|
||||
groupName: "default",
|
||||
createdAt: time(),
|
||||
updatedAt: 0,
|
||||
userData: ['key1' => 'value1', 'key2' => 'value2']
|
||||
);
|
||||
|
||||
// Модель 2
|
||||
$model2 = new UserModel(
|
||||
id: GUID::Parse('3552914c-9ffc-4c73-8946-97c40b0d81b5'),
|
||||
login: "account2",
|
||||
password: "password2",
|
||||
salt: GUID_EMPTY,
|
||||
firstName: "firstName2",
|
||||
middleName: "middleName2",
|
||||
lastName: "lastName2",
|
||||
email: "email2@ya.ru",
|
||||
isEmailVerified: false,
|
||||
groupName: "default",
|
||||
createdAt: time(),
|
||||
updatedAt: 0,
|
||||
userData: ['key1' => 'value3', 'key2' => 4]
|
||||
);
|
||||
|
||||
// Модель 3
|
||||
$model3 = new UserModel(
|
||||
id: GUID::Parse('73828df6-89a3-4feb-ae9a-ef79d0e67cb0'),
|
||||
login: "account3",
|
||||
password: "password3",
|
||||
salt: GUID_EMPTY,
|
||||
firstName: "firstName3",
|
||||
middleName: "middleName3",
|
||||
lastName: "lastName3",
|
||||
email: "email3@ya.ru",
|
||||
isEmailVerified: true,
|
||||
groupName: "default1",
|
||||
createdAt: time(),
|
||||
updatedAt: time(),
|
||||
userData: ['key1' => 1, 'key2' => 2]
|
||||
);
|
||||
|
||||
// Модель 4
|
||||
$model4 = new UserModel(
|
||||
id: GUID::Parse('df39f53f-faff-42cf-bf00-f5855c3e11ec'),
|
||||
login: "account4",
|
||||
password: "password4",
|
||||
salt: GUID_EMPTY,
|
||||
firstName: "firstName4",
|
||||
middleName: "middleName4",
|
||||
lastName: "lastName4",
|
||||
email: "email4@ya.ru",
|
||||
isEmailVerified: true,
|
||||
groupName: "default1",
|
||||
createdAt: time(),
|
||||
updatedAt: time(),
|
||||
userData: ['key1' => 3, 'key2' => '2']
|
||||
);
|
||||
|
||||
/* 2.2. Добавление 1 элемента */
|
||||
// Вставляю $model1
|
||||
$result = $db->Insert($tableName, $model1);
|
||||
|
||||
// Проверяю, успешно ли прошло
|
||||
$this->assertTrue($result !== false);
|
||||
|
||||
// - и совпадает ли идентификатор
|
||||
$this->assertTrue($model1->Id->IsEqualsTo($result));
|
||||
|
||||
/* 2.3. Добавление более 1 элемента */
|
||||
// Массив ожидаемых результатов
|
||||
$expectedResult = [
|
||||
GUID::Parse('3552914c-9ffc-4c73-8946-97c40b0d81b5'),
|
||||
GUID::Parse('73828df6-89a3-4feb-ae9a-ef79d0e67cb0'),
|
||||
GUID::Parse('df39f53f-faff-42cf-bf00-f5855c3e11ec')
|
||||
];
|
||||
|
||||
// Вставляю несколько
|
||||
$result = $db->InsertMany('users', $model2, $model3, $model4);
|
||||
|
||||
// Убеждаюсь, что вставка успешна
|
||||
$this->assertTrue($result !== false);
|
||||
|
||||
// - и все идентификаторы совпадают
|
||||
$this->assertEqualsCanonicalizing($expectedResult, $result);
|
||||
}
|
||||
|
||||
public function testGetRow ()
|
||||
{
|
||||
$this->IncludeReq();
|
||||
|
||||
$db = $this->GetDatabase();
|
||||
|
||||
if (!$db->IsTableExist('users'))
|
||||
die('Таблица не существует. Сперва запустите тест testCreateTable / Table does not exist. Run testCreateTable first');
|
||||
|
||||
if (!$db->IsExist(
|
||||
table: 'users',
|
||||
where: new ConditionBuilder()->WhereEquals('login', 'account1')
|
||||
))
|
||||
die('Записи с логином account1 не существует в таблице users / Record with login account1 is not exists in table users');
|
||||
|
||||
/**
|
||||
* @var false|UserModel $model
|
||||
*/
|
||||
$model = $db->GetRow(
|
||||
table: 'users',
|
||||
where: new ConditionBuilder()->WhereEquals('login', 'account1'),
|
||||
className: '\goodboyalex\php_db_components_pack\tests\data\UserModel'
|
||||
);
|
||||
|
||||
$this->assertTrue($model !== false);
|
||||
$this->assertEquals('account1', $model->Login);
|
||||
$this->assertEquals(
|
||||
'account1', $model->Id->IsEqualsTo(GUID::Parse('8b5dab25-4445-436c-8f25-0f5352cb8500'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetCol ()
|
||||
{
|
||||
$this->IncludeReq();
|
||||
|
||||
$db = $this->GetDatabase();
|
||||
|
||||
if (!$db->IsTableExist('users'))
|
||||
die('Таблица не существует. Сперва запустите тест testCreateTable / Table does not exist. Run testCreateTable first');
|
||||
|
||||
if (!$db->IsExist(
|
||||
table: 'users',
|
||||
where: new ConditionBuilder()
|
||||
->WhereEquals('login', 'account2')
|
||||
->Or()
|
||||
->WhereEquals('login', 'account3')
|
||||
->Or()
|
||||
->WhereEquals('login', 'account4')
|
||||
))
|
||||
die('Записи с логином account1 не существует в таблице users / Record with login account1 is not exists in table users');
|
||||
|
||||
$models = $db->GetCol(
|
||||
table: 'users',
|
||||
column: 'id',
|
||||
where: new ConditionBuilder()->WhereNotEquals('login', 'account1')
|
||||
);
|
||||
|
||||
$this->assertTrue($models !== false);
|
||||
|
||||
$expected = [
|
||||
"3552914c-9ffc-4c73-8946-97c40b0d81b5",
|
||||
"73828df6-89a3-4feb-ae9a-ef79d0e67cb0",
|
||||
"df39f53f-faff-42cf-bf00-f5855c3e11ec"
|
||||
];
|
||||
|
||||
$this->assertEqualsCanonicalizing($expected, $models);
|
||||
}
|
||||
|
||||
public function testGetRows ()
|
||||
{
|
||||
$this->IncludeReq();
|
||||
|
||||
$db = $this->GetDatabase();
|
||||
|
||||
if (!$db->IsTableExist('users'))
|
||||
die('Таблица не существует. Сперва запустите тест testCreateTable / Table does not exist. Run testCreateTable first');
|
||||
|
||||
if (!$db->IsExist(
|
||||
table: 'users',
|
||||
where: new ConditionBuilder()
|
||||
->WhereEquals('login', 'account2')
|
||||
->Or()
|
||||
->WhereEquals('login', 'account3')
|
||||
->Or()
|
||||
->WhereEquals('login', 'account4')
|
||||
))
|
||||
die('Записи с логином account1 не существует в таблице users / Record with login account1 is not exists in table users');
|
||||
|
||||
/**
|
||||
* @var false|ObjectArray $model
|
||||
*/
|
||||
$models = $db->GetRows(
|
||||
table: 'users',
|
||||
where: new ConditionBuilder()->WhereNotEquals('login', 'account1'),
|
||||
className: '\goodboyalex\php_db_components_pack\tests\data\UserModel'
|
||||
);
|
||||
|
||||
$this->assertTrue($models !== false);
|
||||
$this->assertTrue($models->IsExist(fn (UserModel $model) => $model->Login == 'account2'));
|
||||
}
|
||||
|
||||
public function testDropTable ()
|
||||
{
|
||||
$this->IncludeReq();
|
||||
|
||||
$db = $this->GetDatabase();
|
||||
|
||||
$result = $db->DropTable('users');
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testGetValue ()
|
||||
{
|
||||
$this->IncludeReq();
|
||||
|
||||
$db = $this->GetDatabase();
|
||||
|
||||
if (!$db->IsTableExist('users'))
|
||||
die('Таблица не существует. Сперва запустите тест testCreateTable / Table does not exist. Run testCreateTable first');
|
||||
|
||||
if (!$db->IsExist(
|
||||
table: 'users',
|
||||
where: new ConditionBuilder()
|
||||
->WhereEquals('login', 'account2')
|
||||
->Or()
|
||||
->WhereEquals('login', 'account3')
|
||||
->Or()
|
||||
->WhereEquals('login', 'account4')
|
||||
))
|
||||
die('Записи с логином account1 не существует в таблице users / Record with login account1 is not exists in table users');
|
||||
|
||||
$id = $db->GetValue(
|
||||
table: 'users',
|
||||
column: 'id',
|
||||
where: new ConditionBuilder()->WhereEquals('login', 'account2')
|
||||
);
|
||||
|
||||
$this->assertEquals("3552914c-9ffc-4c73-8946-97c40b0d81b5", $id);
|
||||
}
|
||||
|
||||
public function testUpdate ()
|
||||
{
|
||||
$this->IncludeReq();
|
||||
|
||||
$db = $this->GetDatabase();
|
||||
|
||||
if (!$db->IsTableExist('users'))
|
||||
die('Таблица не существует. Сперва запустите тест testCreateTable / Table does not exist. Run testCreateTable first');
|
||||
|
||||
if (!$db->IsExist(
|
||||
table: 'users',
|
||||
where: new ConditionBuilder()->WhereEquals('login', 'account1')
|
||||
))
|
||||
die('Запись с логином account1 не существует в таблице users. Сперва удалите запись с логином account1 (можно использовать метод testDelete) / Record with login account1 already exists in table users. Delete record with login account1 first');
|
||||
|
||||
$model = $db->GetRow(
|
||||
'users',
|
||||
where: new ConditionBuilder()->WhereEquals('login', 'account1'),
|
||||
className: '\goodboyalex\php_db_components_pack\tests\data\UserModel'
|
||||
);
|
||||
|
||||
$this->assertTrue($model !== false);
|
||||
|
||||
$model->Email = 'account1@yandex.ru';
|
||||
|
||||
$result = $db->Update('users', $model);
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testUpdateMany ()
|
||||
{
|
||||
$this->IncludeReq();
|
||||
|
||||
$db = $this->GetDatabase();
|
||||
|
||||
$model1 = $db->GetRow(
|
||||
'users',
|
||||
where: new ConditionBuilder()->WhereEquals('login', 'account2'),
|
||||
className: '\goodboyalex\php_db_components_pack\tests\data\UserModel'
|
||||
);
|
||||
|
||||
$this->assertTrue($model1 !== false);
|
||||
|
||||
$model1->Email = 'account2@yandex.ru';
|
||||
$model1->IsEmailVerified = true;
|
||||
|
||||
$model2 = $db->GetRow(
|
||||
'users',
|
||||
where: new ConditionBuilder()->WhereEquals('login', 'account3'),
|
||||
className: '\goodboyalex\php_db_components_pack\tests\data\UserModel'
|
||||
);
|
||||
|
||||
$this->assertTrue($model2 !== false);
|
||||
|
||||
|
||||
$model2->Email = 'account3@yandex.ru';
|
||||
$model2->IsEmailVerified = true;
|
||||
|
||||
$model3 = $db->GetRow(
|
||||
'users',
|
||||
where: new ConditionBuilder()->WhereEquals('login', 'account4'),
|
||||
className: '\goodboyalex\php_db_components_pack\tests\data\UserModel'
|
||||
);
|
||||
|
||||
$this->assertTrue($model3 !== false);
|
||||
|
||||
$model3->Email = 'account4@yandex.ru';
|
||||
$model3->IsEmailVerified = true;
|
||||
|
||||
|
||||
$result = $db->UpdateMany('users', $model1, $model2, $model3);
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testDelete ()
|
||||
{
|
||||
$this->IncludeReq();
|
||||
|
||||
$db = $this->GetDatabase();
|
||||
|
||||
$result = $db->Delete('users', new ConditionBuilder()->WhereEquals('email_verified', 0));
|
||||
|
||||
$this->assertTrue($result);
|
||||
|
||||
$count = $db->Count('users');
|
||||
$this->assertEquals(3, $count);
|
||||
|
||||
$result = $db->Delete('users');
|
||||
|
||||
$this->assertTrue($result);
|
||||
|
||||
$count = $db->Count('users');
|
||||
$this->assertEquals(0, $count);
|
||||
}
|
||||
|
||||
private function IncludeReq (): void {}
|
||||
|
||||
private function GetDatabase (): Database {}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace goodboyalex\php_db_components_pack\tests\secret_not_in_git;
|
||||
namespace goodboyalex\php_db_components_pack\tests\data;
|
||||
|
||||
use BackedEnum;
|
||||
use goodboyalex\php_components_pack\types\GUID;
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace goodboyalex\php_db_components_pack\tests\secret_not_in_git;
|
||||
namespace goodboyalex\php_db_components_pack\tests\data;
|
||||
|
||||
use goodboyalex\php_components_pack\types\GUID;
|
||||
use goodboyalex\php_db_components_pack\attributes\Compare;
|
||||
@@ -43,10 +43,10 @@
|
||||
* @var GUID $Id Идентификатор пользователя
|
||||
*/
|
||||
#[PrimaryKey, NotNull, DataType(DBType::STRING, 36), ConvertToDB(
|
||||
fromType: ['\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'GUIDToString'],
|
||||
fromType: ['\goodboyalex\php_db_components_pack\tests\data\Converters', 'GUIDToString'],
|
||||
toType: [
|
||||
'\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'GUIDFromString'
|
||||
]), Compare(['\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'IsGUIDEqual']),
|
||||
'\goodboyalex\php_db_components_pack\tests\data\Converters', 'GUIDFromString'
|
||||
]), Compare(['\goodboyalex\php_db_components_pack\tests\data\Converters', 'IsGUIDEqual']),
|
||||
FieldName('id'), DefaultValue(GUID_EMPTY)]
|
||||
public GUID $Id;
|
||||
|
||||
@@ -96,10 +96,10 @@
|
||||
* @var bool $IsEmailVerified Статус подтверждения электронной почты
|
||||
*/
|
||||
#[NotNull, FieldName('email_verified'), DataType(DBType::INT), ConvertToDB(
|
||||
fromType: ['\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'BoolToInt'],
|
||||
toType: ['\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'BoolFromInt']),
|
||||
fromType: ['\goodboyalex\php_db_components_pack\tests\data\Converters', 'BoolToInt'],
|
||||
toType: ['\goodboyalex\php_db_components_pack\tests\data\Converters', 'BoolFromInt']),
|
||||
Compare([
|
||||
'\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'IsBoolEqual'
|
||||
'\goodboyalex\php_db_components_pack\tests\data\Converters', 'IsBoolEqual'
|
||||
]), DefaultValue(0)]
|
||||
public bool $IsEmailVerified = false;
|
||||
|
||||
@@ -125,10 +125,10 @@
|
||||
* @var array $UserData Массив разных данных о пользователе
|
||||
*/
|
||||
#[NotNull, FieldName('data'), DataType(DBType::STRING, 0), ConvertToDB(
|
||||
fromType: ['\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'ArrayToString'],
|
||||
toType: ['\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'ArrayFromString']),
|
||||
fromType: ['\goodboyalex\php_db_components_pack\tests\data\Converters', 'ArrayToString'],
|
||||
toType: ['\goodboyalex\php_db_components_pack\tests\data\Converters', 'ArrayFromString']),
|
||||
Compare([
|
||||
'\goodboyalex\php_db_components_pack\tests\secret_not_in_git\Converters', 'IsArrayEqual'
|
||||
'\goodboyalex\php_db_components_pack\tests\data\Converters', 'IsArrayEqual'
|
||||
]), DefaultValue("[]")]
|
||||
public array $UserData = [];
|
||||
|
13
tests/database_config_sample.php
Normal file
13
tests/database_config_sample.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||
use goodboyalex\php_db_components_pack\models\DBConfig;
|
||||
|
||||
$testConfig = new DBConfig(
|
||||
driver: DBDriver::MySQL, # ВЫБЕРЕТЕ НУЖНЫЙ ДРАЙВЕР
|
||||
host: 'ХОСТ БАЗЫ ДАННЫХ',
|
||||
port: 0, # ПОРТ
|
||||
name: 'ИМЯ БАЗЫ ДАННЫХ',
|
||||
userName: "ПОЛЬЗОВАТЕЛЬ БАЗЫ ДАННЫХ",
|
||||
password: 'ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ'
|
||||
);
|
Reference in New Issue
Block a user