feat: 테넌트 게시판 CRUD 시 메뉴 자동 연동
- MenuService에 게시판 메뉴 연동 메서드 추가 - createMenuForBoard(): 게시판 생성 시 /board 하위에 메뉴 자동 추가 - updateMenuForBoard(): 코드/이름 변경 시 메뉴 URL/이름 동기화 - deleteMenuForBoard(): 게시판 삭제 시 메뉴 Soft Delete - restoreMenuForBoard(): 게시판 복원 시 메뉴 복원 - findParentMenuForBoard(): 부모 메뉴 (/board) 찾기 - BoardService에서 테넌트 게시판 CRUD 시 MenuService 호출 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Models\Boards\Board;
|
||||
use App\Models\Boards\BoardSetting;
|
||||
use App\Services\MenuService;
|
||||
use App\Services\Service;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
@@ -133,6 +134,7 @@ public function createSystemBoard(array $data): Board
|
||||
|
||||
/**
|
||||
* 테넌트 게시판 생성 (sam용)
|
||||
* - 게시판 생성 후 메뉴 자동 생성
|
||||
*/
|
||||
public function createTenantBoard(array $data): Board
|
||||
{
|
||||
@@ -140,7 +142,16 @@ public function createTenantBoard(array $data): Board
|
||||
$data['tenant_id'] = $this->tenantId();
|
||||
$data['created_by'] = $this->apiUserId();
|
||||
|
||||
return Board::create($data);
|
||||
$board = Board::create($data);
|
||||
|
||||
// 메뉴 자동 생성
|
||||
MenuService::createMenuForBoard(
|
||||
$board->board_code,
|
||||
$board->name,
|
||||
$board->tenant_id
|
||||
);
|
||||
|
||||
return $board;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
@@ -166,6 +177,7 @@ public function updateSystemBoard(int $id, array $data): ?Board
|
||||
|
||||
/**
|
||||
* 테넌트 게시판 수정 (sam용)
|
||||
* - 코드/이름 변경 시 메뉴도 자동 수정
|
||||
*/
|
||||
public function updateTenantBoard(int $id, array $data): ?Board
|
||||
{
|
||||
@@ -175,9 +187,26 @@ public function updateTenantBoard(int $id, array $data): ?Board
|
||||
return null;
|
||||
}
|
||||
|
||||
// 기존 코드/이름 저장 (메뉴 업데이트용)
|
||||
$oldCode = $board->board_code;
|
||||
$oldName = $board->name;
|
||||
|
||||
$data['updated_by'] = $this->apiUserId();
|
||||
$board->update($data);
|
||||
|
||||
// 코드 또는 이름 변경 시 메뉴도 업데이트
|
||||
$newCode = $data['board_code'] ?? $oldCode;
|
||||
$newName = $data['name'] ?? $oldName;
|
||||
|
||||
if ($oldCode !== $newCode || $oldName !== $newName) {
|
||||
MenuService::updateMenuForBoard(
|
||||
$oldCode,
|
||||
$newCode,
|
||||
$newName,
|
||||
$board->tenant_id
|
||||
);
|
||||
}
|
||||
|
||||
return $board->fresh();
|
||||
}
|
||||
|
||||
@@ -205,6 +234,7 @@ public function deleteSystemBoard(int $id): bool
|
||||
|
||||
/**
|
||||
* 테넌트 게시판 삭제 (sam용)
|
||||
* - 게시판 삭제 시 메뉴도 자동 삭제 (Soft Delete)
|
||||
*/
|
||||
public function deleteTenantBoard(int $id): bool
|
||||
{
|
||||
@@ -214,10 +244,16 @@ public function deleteTenantBoard(int $id): bool
|
||||
return false;
|
||||
}
|
||||
|
||||
$boardCode = $board->board_code;
|
||||
$tenantId = $board->tenant_id;
|
||||
|
||||
$board->deleted_by = $this->apiUserId();
|
||||
$board->save();
|
||||
$board->delete();
|
||||
|
||||
// 메뉴도 함께 삭제 (Soft Delete)
|
||||
MenuService::deleteMenuForBoard($boardCode, $tenantId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -426,4 +426,171 @@ public static function trashedList(array $params = [])
|
||||
->orderBy('deleted_at', 'desc')
|
||||
->get();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 게시판 메뉴 연동 메서드 (테넌트 게시판 전용)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* 테넌트 게시판용 메뉴 생성
|
||||
*
|
||||
* @param string $boardCode 게시판 코드
|
||||
* @param string $boardName 게시판 이름
|
||||
* @param int $tenantId 테넌트 ID
|
||||
* @return Menu|null 생성된 메뉴 또는 null (중복 시)
|
||||
*/
|
||||
public static function createMenuForBoard(string $boardCode, string $boardName, int $tenantId): ?Menu
|
||||
{
|
||||
$url = '/boards/'.$boardCode;
|
||||
$userId = self::actorId();
|
||||
|
||||
// 중복 체크
|
||||
if (Menu::where('url', $url)->where('tenant_id', $tenantId)->exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 부모 메뉴 찾기
|
||||
$parentId = self::findParentMenuForBoard($tenantId);
|
||||
|
||||
// 정렬 순서 계산
|
||||
$maxOrder = Menu::where('tenant_id', $tenantId)
|
||||
->where('parent_id', $parentId)
|
||||
->max('sort_order') ?? 0;
|
||||
|
||||
return Menu::create([
|
||||
'tenant_id' => $tenantId,
|
||||
'parent_id' => $parentId,
|
||||
'name' => $boardName,
|
||||
'url' => $url,
|
||||
'icon' => 'document-text',
|
||||
'sort_order' => $maxOrder + 1,
|
||||
'is_active' => true,
|
||||
'hidden' => false,
|
||||
'is_external' => false,
|
||||
'created_by' => $userId,
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 테넌트 게시판 메뉴의 부모 메뉴 ID 찾기
|
||||
* 우선순위: /board → /boards → /customer-center → null (최상위)
|
||||
*
|
||||
* @param int $tenantId 테넌트 ID
|
||||
* @return int|null 부모 메뉴 ID
|
||||
*/
|
||||
protected static function findParentMenuForBoard(int $tenantId): ?int
|
||||
{
|
||||
$priorityUrls = ['/board', '/boards', '/customer-center'];
|
||||
|
||||
foreach ($priorityUrls as $url) {
|
||||
$menu = Menu::where('tenant_id', $tenantId)
|
||||
->where('url', $url)
|
||||
->first();
|
||||
|
||||
if ($menu) {
|
||||
return $menu->id;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 테넌트 게시판용 메뉴 수정 (코드/이름 변경 시)
|
||||
*
|
||||
* @param string $oldCode 기존 게시판 코드
|
||||
* @param string $newCode 새 게시판 코드
|
||||
* @param string $newName 새 게시판 이름
|
||||
* @param int $tenantId 테넌트 ID
|
||||
* @return bool 수정 성공 여부
|
||||
*/
|
||||
public static function updateMenuForBoard(string $oldCode, string $newCode, string $newName, int $tenantId): bool
|
||||
{
|
||||
$oldUrl = '/boards/'.$oldCode;
|
||||
$newUrl = '/boards/'.$newCode;
|
||||
|
||||
$menu = Menu::where('url', $oldUrl)
|
||||
->where('tenant_id', $tenantId)
|
||||
->first();
|
||||
|
||||
if (! $menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$menu->url = $newUrl;
|
||||
$menu->name = $newName;
|
||||
$menu->updated_by = self::actorId();
|
||||
$menu->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 테넌트 게시판용 메뉴 삭제 (Soft Delete)
|
||||
*
|
||||
* @param string $boardCode 게시판 코드
|
||||
* @param int $tenantId 테넌트 ID
|
||||
* @param bool $forceDelete 영구 삭제 여부
|
||||
* @return bool 삭제 성공 여부
|
||||
*/
|
||||
public static function deleteMenuForBoard(string $boardCode, int $tenantId, bool $forceDelete = false): bool
|
||||
{
|
||||
$url = '/boards/'.$boardCode;
|
||||
|
||||
$query = $forceDelete
|
||||
? Menu::withTrashed()->where('url', $url)->where('tenant_id', $tenantId)
|
||||
: Menu::where('url', $url)->where('tenant_id', $tenantId);
|
||||
|
||||
$menu = $query->first();
|
||||
|
||||
if (! $menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $forceDelete) {
|
||||
$menu->deleted_by = self::actorId();
|
||||
$menu->save();
|
||||
}
|
||||
|
||||
return $forceDelete ? $menu->forceDelete() : $menu->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 테넌트 게시판용 메뉴 복원
|
||||
*
|
||||
* @param string $boardCode 게시판 코드
|
||||
* @param string $boardName 게시판 이름
|
||||
* @param int $tenantId 테넌트 ID
|
||||
* @return bool 복원 성공 여부
|
||||
*/
|
||||
public static function restoreMenuForBoard(string $boardCode, string $boardName, int $tenantId): bool
|
||||
{
|
||||
$url = '/boards/'.$boardCode;
|
||||
|
||||
// 1. soft-deleted 메뉴 확인
|
||||
$trashedMenu = Menu::onlyTrashed()
|
||||
->where('url', $url)
|
||||
->where('tenant_id', $tenantId)
|
||||
->first();
|
||||
|
||||
if ($trashedMenu) {
|
||||
$trashedMenu->restore();
|
||||
$trashedMenu->deleted_by = null;
|
||||
$trashedMenu->updated_by = self::actorId();
|
||||
$trashedMenu->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. 이미 활성 메뉴가 있는지 확인
|
||||
if (Menu::where('url', $url)->where('tenant_id', $tenantId)->exists()) {
|
||||
return true; // 이미 존재하면 성공으로 처리
|
||||
}
|
||||
|
||||
// 3. 둘 다 없으면 새로 생성
|
||||
$newMenu = self::createMenuForBoard($boardCode, $boardName, $tenantId);
|
||||
|
||||
return $newMenu !== null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user