ultimatepos/Modules/ProfessionalProject/Entities/PpProjectCategory.php

151 lines
4.3 KiB
PHP

<?php
namespace Modules\ProfessionalProject\Entities;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
class PpProjectCategory extends Model
{
protected $table = 'pp_project_categories';
protected $guarded = ['id'];
public function projects()
{
return $this->belongsToMany(PpProject::class, 'pp_project_category', 'category_id', 'project_id');
}
public function members()
{
return $this->belongsToMany(\App\User::class, 'pp_project_category_members', 'category_id', 'user_id');
}
public function creator()
{
return $this->belongsTo(\App\User::class, 'created_by');
}
public function parent()
{
return $this->belongsTo(self::class, 'parent_id');
}
public function children()
{
return $this->hasMany(self::class, 'parent_id')->orderBy('position')->orderBy('name');
}
public function scopeForBusiness($query, $business_id)
{
return $query->where('business_id', $business_id);
}
public function scopeRoots($query)
{
return $query->whereNull('parent_id');
}
public function isRoot(): bool
{
return empty($this->parent_id);
}
public function hasChildren(): bool
{
if ($this->relationLoaded('children')) {
return $this->children->isNotEmpty();
}
return $this->children()->exists();
}
/**
* @return int[]
*/
public static function descendantIds(int $business_id, int $category_id): array
{
$by_parent = self::forBusiness($business_id)->get(['id', 'parent_id'])->groupBy('parent_id');
$ids = [];
$queue = [$category_id];
while (! empty($queue)) {
$current = array_shift($queue);
foreach ($by_parent->get($current, collect()) as $child) {
$ids[] = $child->id;
$queue[] = $child->id;
}
}
return $ids;
}
/**
* @return Collection<int, self>
*/
public static function breadcrumb(int $business_id, ?int $category_id): Collection
{
if (empty($category_id)) {
return collect();
}
$map = self::forBusiness($business_id)->get(['id', 'parent_id', 'name'])->keyBy('id');
$trail = collect();
$current = $map->get($category_id);
while ($current) {
$trail->prepend($current);
$current = $current->parent_id ? $map->get($current->parent_id) : null;
}
return $trail;
}
public static function treeDropdown(int $business_id, ?int $exclude_id = null, ?int $prefix_id = null): array
{
$roots = self::forBusiness($business_id)->roots()->orderBy('position')->orderBy('name')->get();
$all = self::forBusiness($business_id)->orderBy('position')->orderBy('name')->get()->groupBy('parent_id');
$exclude = $exclude_id ? array_merge([$exclude_id], self::descendantIds($business_id, $exclude_id)) : [];
$options = [];
$walk = function ($nodes, $depth = 0) use (&$walk, &$options, $all, $exclude) {
foreach ($nodes as $node) {
if (in_array($node->id, $exclude, true)) {
continue;
}
$options[$node->id] = str_repeat('— ', $depth).$node->name;
$walk($all->get($node->id, collect()), $depth + 1);
}
};
$walk($roots);
return $options;
}
public static function dropdown($business_id)
{
return collect(self::treeDropdown($business_id));
}
/**
* @return Collection<int, self>
*/
public static function treeForBusiness(int $business_id): Collection
{
$all = self::forBusiness($business_id)->orderBy('position')->orderBy('name')->get();
return self::buildTree($all);
}
public static function buildTree(Collection $categories, ?int $parent_id = null): Collection
{
return ($parent_id === null ? $categories->whereNull('parent_id') : $categories->where('parent_id', $parent_id))
->values()
->map(function ($category) use ($categories) {
$category->setRelation('children', self::buildTree($categories, $category->id));
return $category;
});
}
}