Files
finansePRO/app/Models/CategoryModel.php
T
2026-07-12 19:21:35 +02:00

89 lines
3.0 KiB
PHP

<?php
namespace App\Models;
use CodeIgniter\Model;
class CategoryModel extends Model
{
protected $table = 'categories';
protected $primaryKey = 'id';
protected $returnType = 'array';
protected $useTimestamps = true;
protected $allowedFields = ['name', 'type', 'parent_id'];
protected $validationRules = [
'name' => 'required|max_length[100]',
'type' => 'required|in_list[income,expense]',
'parent_id' => 'permit_empty|is_natural_no_zero',
];
/**
* Plaska lista kategorii, opcjonalnie filtrowana typem.
*/
public function flatList(?string $type = null): array
{
$builder = $this->orderBy('type', 'ASC')->orderBy('name', 'ASC');
if ($type !== null && $type !== '') {
$builder = $builder->where('type', $type);
}
return $builder->findAll();
}
/**
* Czy kategoria jest uzywana przez jakies operacje.
*/
public function usedByOperations(int $id): bool
{
return (bool) model(OperationModel::class)->where('category_id', $id)->countAllResults();
}
/**
* Kategorie w porzadku drzewa, posortowane po nazwie na kazdym poziomie.
* Kazdy element dostaje 'depth' oraz 'indent_label' (nazwa z wcieciem) do list i selectow.
*/
public function tree(?string $type = null): array
{
$builder = $this->orderBy('name', 'ASC');
if ($type !== null && $type !== '') {
$builder->where('type', $type);
}
$all = $builder->findAll();
// Grupowanie dzieci wg rodzica (0 = korzen)
$childrenByParent = [];
foreach ($all as $c) {
$childrenByParent[(int) ($c['parent_id'] ?: 0)][] = $c;
}
$indent = "\u{00A0}\u{00A0}\u{00A0}\u{00A0}"; // 4x twarda spacja na poziom
$out = [];
$walk = static function (int $parentId, int $depth, string $parentPath) use (&$walk, &$out, $childrenByParent, $indent): void {
foreach ($childrenByParent[$parentId] ?? [] as $c) {
$c['depth'] = $depth;
$c['indent_label'] = str_repeat($indent, $depth) . $c['name'];
// Pelna sciezka "Nadrzedna → Podrzedna" — jednoznaczna nawet gdy JS uciasnie wciecia.
$c['path_label'] = $parentPath === '' ? $c['name'] : $parentPath . ' → ' . $c['name'];
$out[] = $c;
$walk((int) $c['id'], $depth + 1, $c['path_label']);
}
};
$walk(0, 0, '');
// Sieroty (np. rodzic odfiltrowany typem) — dopnij na koncu bez wciecia
$seen = array_column($out, null, 'id');
foreach ($all as $c) {
if (! isset($seen[$c['id']])) {
$c['depth'] = 0;
$c['indent_label'] = $c['name'];
$c['path_label'] = $c['name'];
$out[] = $c;
}
}
return $out;
}
}