209 lines
6.5 KiB
PHP
209 lines
6.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Commons\Category;
|
|
use App\Models\Commons\CategoryTemplate;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
|
|
|
class CategoryTemplateService extends Service
|
|
{
|
|
public function index(int $categoryId, array $params)
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$size = (int) ($params['size'] ?? 20);
|
|
|
|
return CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)
|
|
->where('category_id', $categoryId)
|
|
->orderByDesc('version_no')
|
|
->paginate($size);
|
|
}
|
|
|
|
public function store(int $categoryId, array $data)
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$userId = $this->apiUserId();
|
|
$this->assertCategoryExists($tenantId, $categoryId);
|
|
|
|
$v = Validator::make($data, [
|
|
'version_no' => 'required|integer|min:1',
|
|
'template_json' => 'required|json',
|
|
'applied_at' => 'required|date',
|
|
'remarks' => 'nullable|string|max:255',
|
|
]);
|
|
$payload = $v->validate();
|
|
|
|
$dup = CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)
|
|
->where('category_id', $categoryId)
|
|
->where('version_no', $payload['version_no'])
|
|
->exists();
|
|
if ($dup) {
|
|
throw new BadRequestHttpException(__('error.duplicate_key')); // version_no 중복
|
|
}
|
|
|
|
$payload['tenant_id'] = $tenantId;
|
|
$payload['category_id'] = $categoryId;
|
|
$payload['created_by'] = $userId;
|
|
|
|
return CategoryTemplate::create($payload);
|
|
}
|
|
|
|
public function show(int $tplId)
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
|
|
$tpl = CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)
|
|
->find($tplId);
|
|
|
|
if (! $tpl) {
|
|
throw new BadRequestHttpException(__('error.not_found'));
|
|
}
|
|
|
|
return $tpl;
|
|
}
|
|
|
|
public function update(int $tplId, array $data)
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$userId = $this->apiUserId();
|
|
|
|
$tpl = CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)
|
|
->find($tplId);
|
|
|
|
if (! $tpl) {
|
|
throw new BadRequestHttpException(__('error.not_found'));
|
|
}
|
|
|
|
$v = Validator::make($data, [
|
|
'template_json' => 'nullable|json',
|
|
'applied_at' => 'nullable|date',
|
|
'remarks' => 'nullable|string|max:255',
|
|
]);
|
|
$payload = $v->validate();
|
|
$payload['updated_by'] = $userId;
|
|
|
|
$tpl->update($payload);
|
|
|
|
return $tpl->refresh();
|
|
}
|
|
|
|
public function destroy(int $tplId): void
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
|
|
$tpl = CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)
|
|
->find($tplId);
|
|
|
|
if (! $tpl) {
|
|
throw new BadRequestHttpException(__('error.not_found'));
|
|
}
|
|
$tpl->delete();
|
|
}
|
|
|
|
/**
|
|
* 적용 정책:
|
|
* - categories.active_template_version (또는 별도 맵 테이블)에 version_no 반영
|
|
* - (옵션) template_json 기반으로 category_fields를 실제로 갱신하려면 여기서 동기화
|
|
*/
|
|
public function apply(int $categoryId, int $tplId): void
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$userId = $this->apiUserId();
|
|
|
|
$tpl = CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)
|
|
->where('category_id', $categoryId)
|
|
->find($tplId);
|
|
|
|
if (! $tpl) {
|
|
throw new BadRequestHttpException(__('error.not_found'));
|
|
}
|
|
|
|
DB::transaction(function () {
|
|
// 1) categories 테이블에 활성 버전 반영(컬럼이 있다면)
|
|
// Category::where('tenant_id', $tenantId)->where('id', $categoryId)->update([
|
|
// 'active_template_version' => $tpl->version_no,
|
|
// 'updated_by' => $userId,
|
|
// ]);
|
|
|
|
// 2) (선택) template_json → category_fields 동기화
|
|
// - 추가/수정/삭제 전략은 운영정책에 맞게 구현
|
|
// - 여기서는 예시로 "fields" 배열만 처리
|
|
// $snapshot = json_decode($tpl->template_json, true);
|
|
// foreach (($snapshot['fields'] ?? []) as $i => $f) {
|
|
// // key, name, type, required, default, options 매핑 ...
|
|
// }
|
|
});
|
|
}
|
|
|
|
public function preview(int $categoryId, int $tplId): array
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
|
|
$tpl = CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)
|
|
->where('category_id', $categoryId)
|
|
->find($tplId);
|
|
|
|
if (! $tpl) {
|
|
throw new BadRequestHttpException(__('error.not_found'));
|
|
}
|
|
|
|
$json = json_decode($tpl->template_json, true);
|
|
if (! is_array($json)) {
|
|
throw new BadRequestHttpException(__('error.invalid_payload'));
|
|
}
|
|
|
|
// 프론트 렌더링 편의 구조로 가공 가능
|
|
return $json;
|
|
}
|
|
|
|
public function diff(int $categoryId, int $a, int $b): array
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
|
|
$aTpl = CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)->where('category_id', $categoryId)
|
|
->where('version_no', $a)->first();
|
|
|
|
$bTpl = CategoryTemplate::query()
|
|
->where('tenant_id', $tenantId)->where('category_id', $categoryId)
|
|
->where('version_no', $b)->first();
|
|
|
|
if (! $aTpl || ! $bTpl) {
|
|
throw new BadRequestHttpException(__('error.not_found'));
|
|
}
|
|
|
|
$aj = json_decode($aTpl->template_json, true) ?: [];
|
|
$bj = json_decode($bTpl->template_json, true) ?: [];
|
|
|
|
// 아주 단순한 diff 예시 (fields 키만 비교)
|
|
$aKeys = collect($aj['fields'] ?? [])->pluck('key')->all();
|
|
$bKeys = collect($bj['fields'] ?? [])->pluck('key')->all();
|
|
|
|
return [
|
|
'added' => array_values(array_diff($bKeys, $aKeys)),
|
|
'removed' => array_values(array_diff($aKeys, $bKeys)),
|
|
// 변경(diff in detail)은 정책에 맞게 확장
|
|
];
|
|
}
|
|
|
|
private function assertCategoryExists(int $tenantId, int $categoryId): void
|
|
{
|
|
$exists = Category::query()
|
|
->where('tenant_id', $tenantId)
|
|
->where('id', $categoryId)
|
|
->exists();
|
|
if (! $exists) {
|
|
throw new BadRequestHttpException(__('error.category_not_found'));
|
|
}
|
|
}
|
|
}
|