102 lines
3.6 KiB
PHP
102 lines
3.6 KiB
PHP
<?php
|
||
/**
|
||
* @package Bicycle
|
||
* @author Egor Isaev
|
||
* @description CategoryRepository.php
|
||
* @copyright (c) 11/08/2026
|
||
*/
|
||
|
||
namespace App\Repositories;
|
||
|
||
use System\Classes\Repository;
|
||
|
||
/**
|
||
* Репозиторий таблицы categories (статьи income/expense, с подкатегориями через parent_id).
|
||
*/
|
||
class CategoryRepository extends Repository
|
||
{
|
||
/**
|
||
* @param string|null $connection Имя подключения (Database::instance($connection)); null — по умолчанию
|
||
*/
|
||
public function __construct(?string $connection = null)
|
||
{
|
||
parent::__construct('categories', connection: $connection);
|
||
}
|
||
|
||
/**
|
||
* Активная (is_delete=0) статья с тем же названием у пользователя, в рамках type+parent_id.
|
||
*
|
||
* @param int $user_id
|
||
* @param string $type income|expense
|
||
* @param int|null $parent_id null — верхний уровень
|
||
* @param string $title
|
||
* @param int|null $exclude_id Исключить этот id (правка своего же названия — не дубль)
|
||
* @return object|false
|
||
*/
|
||
public function findActiveDuplicate(int $user_id, string $type, ?int $parent_id, string $title, ?int $exclude_id = null): mixed
|
||
{
|
||
return $this->findDuplicate($user_id, $type, $parent_id, $title, false, $exclude_id);
|
||
}
|
||
|
||
/**
|
||
* Архивная (is_delete=1) статья с тем же названием у пользователя.
|
||
*
|
||
* @param int $user_id
|
||
* @param string $type income|expense
|
||
* @param int|null $parent_id
|
||
* @param string $title
|
||
* @param int|null $exclude_id
|
||
* @return object|false
|
||
*/
|
||
public function findArchivedDuplicate(int $user_id, string $type, ?int $parent_id, string $title, ?int $exclude_id = null): mixed
|
||
{
|
||
return $this->findDuplicate($user_id, $type, $parent_id, $title, true, $exclude_id);
|
||
}
|
||
|
||
/**
|
||
* @param int $user_id
|
||
* @param string $type
|
||
* @param int|null $parent_id
|
||
* @param string $title
|
||
* @param bool $is_delete
|
||
* @param int|null $exclude_id
|
||
* @return object|false
|
||
*/
|
||
protected function findDuplicate(int $user_id, string $type, ?int $parent_id, string $title, bool $is_delete, ?int $exclude_id): mixed
|
||
{
|
||
$pdo = $this->pdo->pdo();
|
||
|
||
$where = "user_id = $user_id"
|
||
. ' AND type = ' . $pdo->quote($type)
|
||
. ' AND is_delete = ' . ($is_delete ? 1 : 0)
|
||
. ' AND title = ' . $pdo->quote($title)
|
||
. ' AND parent_id ' . ($parent_id === null ? 'IS NULL' : "= $parent_id");
|
||
|
||
if ($exclude_id !== null) {
|
||
$where .= " AND id != $exclude_id";
|
||
}
|
||
|
||
return $this->getItemWhere($where);
|
||
}
|
||
|
||
/**
|
||
* Активные статьи пользователя, сгруппированные по parent_id (0 — верхний уровень, вместо null,
|
||
* чтобы использовать как ключ массива) — для рендера дерева на странице статей.
|
||
*
|
||
* @param int $user_id
|
||
* @return array<int,object[]>
|
||
*/
|
||
public function getTree(int $user_id): array
|
||
{
|
||
$categories = $this->getList('*', ['user_id' => $user_id, 'is_delete' => 0], '`order`');
|
||
$tree = [];
|
||
|
||
foreach ($categories ?: [] as $category) {
|
||
$key = $category->parent_id === null ? 0 : (int)$category->parent_id;
|
||
$tree[$key][] = $category;
|
||
}
|
||
|
||
return $tree;
|
||
}
|
||
}
|