'integer', 'parent_id' => 'integer', 'child_id' => 'integer', 'order_no' => 'integer', 'metadata' => 'array', 'created_at' => 'datetime', 'updated_at' => 'datetime', ]; // 엔티티 타입 상수 public const TYPE_PAGE = 'page'; public const TYPE_SECTION = 'section'; public const TYPE_FIELD = 'field'; public const TYPE_BOM = 'bom'; // 그룹 ID 상수 public const GROUP_ITEM_MASTER = 1; /** * 부모 엔티티 조회 (Polymorphic) */ public function parent() { return $this->morphTo('parent', 'parent_type', 'parent_id'); } /** * 자식 엔티티 조회 (Polymorphic) */ public function child() { return $this->morphTo('child', 'child_type', 'child_id'); } /** * 부모 타입에 따른 모델 클래스 반환 */ public static function getModelClass(string $type): ?string { return match ($type) { self::TYPE_PAGE => ItemPage::class, self::TYPE_SECTION => ItemSection::class, self::TYPE_FIELD => ItemField::class, self::TYPE_BOM => ItemBomItem::class, default => null, }; } /** * 특정 부모의 자식 관계 조회 */ public static function getChildren(string $parentType, int $parentId, ?string $childType = null) { $query = self::where('parent_type', $parentType) ->where('parent_id', $parentId) ->orderBy('order_no'); if ($childType) { $query->where('child_type', $childType); } return $query; } /** * 특정 자식의 부모 관계 조회 */ public static function getParents(string $childType, int $childId, ?string $parentType = null) { $query = self::where('child_type', $childType) ->where('child_id', $childId); if ($parentType) { $query->where('parent_type', $parentType); } return $query; } /** * 관계 생성 또는 업데이트 */ public static function link( int $tenantId, string $parentType, int $parentId, string $childType, int $childId, int $orderNo = 0, ?array $metadata = null, int $groupId = self::GROUP_ITEM_MASTER ): self { return self::updateOrCreate( [ 'tenant_id' => $tenantId, 'group_id' => $groupId, 'parent_type' => $parentType, 'parent_id' => $parentId, 'child_type' => $childType, 'child_id' => $childId, ], [ 'order_no' => $orderNo, 'metadata' => $metadata, ] ); } /** * 관계 해제 */ public static function unlink( int $tenantId, string $parentType, int $parentId, string $childType, int $childId, int $groupId = self::GROUP_ITEM_MASTER ): bool { return self::where([ 'tenant_id' => $tenantId, 'group_id' => $groupId, 'parent_type' => $parentType, 'parent_id' => $parentId, 'child_type' => $childType, 'child_id' => $childId, ])->delete() > 0; } /** * 특정 부모의 모든 자식 관계 해제 */ public static function unlinkAllChildren( int $tenantId, string $parentType, int $parentId, ?string $childType = null, int $groupId = self::GROUP_ITEM_MASTER ): int { $query = self::where([ 'tenant_id' => $tenantId, 'group_id' => $groupId, 'parent_type' => $parentType, 'parent_id' => $parentId, ]); if ($childType) { $query->where('child_type', $childType); } return $query->delete(); } }