246 lines
9.5 KiB
PHP
246 lines
9.5 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Models\PCBuild;
|
||
use App\Models\Component;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\DB;
|
||
use App\Services\BuildValidator;
|
||
|
||
class PCBuildsController extends Controller
|
||
{
|
||
/**
|
||
* @OA\Get(
|
||
* path="/api/builds",
|
||
* summary="Получить список своих сборок",
|
||
* tags={"PC Builds"},
|
||
* @OA\Response(response=200, description="Список сборок"),
|
||
* @OA\Response(response=401, description="Неавторизован")
|
||
* )
|
||
*/
|
||
public function index()
|
||
{
|
||
$builds = PCBuild::where('user_id', auth()->id())
|
||
->with('components')
|
||
->get();
|
||
|
||
return response()->json($builds);
|
||
}
|
||
|
||
/**
|
||
* @OA\Post(
|
||
* path="/api/builds",
|
||
* summary="Создать новую сборку",
|
||
* tags={"PC Builds"},
|
||
* @OA\RequestBody(
|
||
* required=true,
|
||
* @OA\JsonContent(
|
||
* required={"name", "component_ids"},
|
||
* @OA\Property(property="name", type="string", example="Игровой ПК 2025"),
|
||
* @OA\Property(property="description", type="string", nullable=true, example="Для игр в 1440p"),
|
||
* @OA\Property(property="component_ids", type="array", @OA\Items(type="integer", example=1)),
|
||
* @OA\Property(property="is_ai_generated", type="boolean", default=false),
|
||
* @OA\Property(property="ai_prompt", type="string", nullable=true, example="Сборка до 1000$ для игр")
|
||
* )
|
||
* ),
|
||
* @OA\Response(response=201, description="Сборка создана"),
|
||
* @OA\Response(response=400, description="Ошибка валидации"),
|
||
* @OA\Response(response=403, description="Запрещено: чужие компоненты")
|
||
* )
|
||
*/
|
||
public function store(Request $request)
|
||
{
|
||
$validated = $request->validate([
|
||
'name' => 'required|string|max:255',
|
||
'description' => 'nullable|string',
|
||
'component_ids' => 'required|array|min:1',
|
||
'component_ids.*' => 'exists:components,id',
|
||
'is_ai_generated' => 'nullable|boolean',
|
||
'ai_prompt' => 'nullable|string',
|
||
]);
|
||
|
||
// Проверяем: все компоненты — либо официальные, либо ваши
|
||
$invalidComponents = Component::whereIn('id', $validated['component_ids'])
|
||
->where(function ($query) {
|
||
$query->where('is_official', false)
|
||
->where('created_by_user_id', '!=', auth()->id());
|
||
})
|
||
->pluck('name', 'id')
|
||
->toArray();
|
||
|
||
if (!empty($invalidComponents)) {
|
||
return response()->json([
|
||
'message' => 'Запрещено использовать неофициальные компоненты, созданные другими пользователями.',
|
||
'invalid_components' => $invalidComponents
|
||
], 403);
|
||
}
|
||
|
||
// 👇 ВСТАВЛЯЕМ ПРОВЕРКУ СОВМЕСТИМОСТИ ЗДЕСЬ — ПЕРЕД СОЗДАНИЕМ СБОРКИ
|
||
$validator = new BuildValidator();
|
||
$compatibility = $validator->validateCompatibility($validated['component_ids']);
|
||
|
||
if (!$compatibility['valid']) {
|
||
return response()->json([
|
||
'message' => 'Сборка содержит несовместимые компоненты.',
|
||
'errors' => $compatibility['errors'],
|
||
'warnings' => $compatibility['warnings']
|
||
], 422); // 422 Unprocessable Entity
|
||
}
|
||
|
||
// ✅ Только если совместимость OK — создаём сборку
|
||
$build = PCBuild::create([
|
||
'user_id' => auth()->id(),
|
||
'name' => $validated['name'],
|
||
'description' => $validated['description'] ?? null,
|
||
'is_ai_generated' => $validated['is_ai_generated'] ?? false,
|
||
'ai_prompt' => $validated['ai_prompt'] ?? null,
|
||
]);
|
||
|
||
$build->components()->attach($validated['component_ids']);
|
||
|
||
return response()->json([
|
||
'message' => 'Сборка успешно создана.',
|
||
'build' => $build->load('components'),
|
||
'compatibility' => $compatibility // опционально — для отладки
|
||
], 201);
|
||
}
|
||
|
||
/**
|
||
* @OA\Get(
|
||
* path="/api/builds/{id}",
|
||
* summary="Получить одну сборку по ID",
|
||
* tags={"PC Builds"},
|
||
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
|
||
* @OA\Response(response=200, description="Сборка найдена"),
|
||
* @OA\Response(response=403, description="Запрещено: не ваша сборка"),
|
||
* @OA\Response(response=404, description="Не найдено")
|
||
* )
|
||
*/
|
||
public function show($id)
|
||
{
|
||
$build = PCBuild::with('components')->findOrFail($id);
|
||
|
||
if ($build->user_id !== auth()->id()) {
|
||
return response()->json([
|
||
'message' => 'Вы не можете просматривать эту сборку.'
|
||
], 403);
|
||
}
|
||
|
||
return response()->json($build);
|
||
}
|
||
|
||
/**
|
||
* @OA\Put(
|
||
* path="/api/builds/{id}",
|
||
* summary="Обновить сборку",
|
||
* tags={"PC Builds"},
|
||
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
|
||
* @OA\RequestBody(
|
||
* required=true,
|
||
* @OA\JsonContent(
|
||
* required={"name", "component_ids"},
|
||
* @OA\Property(property="name", type="string"),
|
||
* @OA\Property(property="description", type="string", nullable=true),
|
||
* @OA\Property(property="component_ids", type="array", @OA\Items(type="integer")),
|
||
* @OA\Property(property="is_ai_generated", type="boolean"),
|
||
* @OA\Property(property="ai_prompt", type="string", nullable=true)
|
||
* )
|
||
* ),
|
||
* @OA\Response(response=200, description="Сборка обновлена"),
|
||
* @OA\Response(response=403, description="Запрещено")
|
||
* )
|
||
*/
|
||
public function update(Request $request, $id)
|
||
{
|
||
$build = PCBuild::findOrFail($id);
|
||
|
||
if ($build->user_id !== auth()->id()) {
|
||
return response()->json([
|
||
'message' => 'Вы не можете редактировать эту сборку.'
|
||
], 403);
|
||
}
|
||
|
||
$validated = $request->validate([
|
||
'name' => 'required|string|max:255',
|
||
'description' => 'nullable|string',
|
||
'component_ids' => 'required|array|min:1',
|
||
'component_ids.*' => 'exists:components,id',
|
||
'is_ai_generated' => 'nullable|boolean',
|
||
'ai_prompt' => 'nullable|string',
|
||
]);
|
||
|
||
// Проверка: все компоненты — либо официальные, либо ваши
|
||
$invalidComponents = Component::whereIn('id', $validated['component_ids'])
|
||
->where(function ($query) {
|
||
$query->where('is_official', false)
|
||
->where('created_by_user_id', '!=', auth()->id());
|
||
})
|
||
->pluck('name', 'id')
|
||
->toArray();
|
||
|
||
if (!empty($invalidComponents)) {
|
||
return response()->json([
|
||
'message' => 'Запрещено использовать неофициальные компоненты, созданные другими пользователями.',
|
||
'invalid_components' => $invalidComponents
|
||
], 403);
|
||
}
|
||
|
||
// 👇 ВСТАВЛЯЕМ ПРОВЕРКУ СОВМЕСТИМОСТИ ЗДЕСЬ — ПЕРЕД ОБНОВЛЕНИЕМ
|
||
$validator = new BuildValidator();
|
||
$compatibility = $validator->validateCompatibility($validated['component_ids']);
|
||
|
||
if (!$compatibility['valid']) {
|
||
return response()->json([
|
||
'message' => 'Сборка содержит несовместимые компоненты.',
|
||
'errors' => $compatibility['errors'],
|
||
'warnings' => $compatibility['warnings']
|
||
], 422);
|
||
}
|
||
|
||
// ✅ Обновляем сборку
|
||
DB::transaction(function () use ($build, $validated) {
|
||
$build->update([
|
||
'name' => $validated['name'],
|
||
'description' => $validated['description'] ?? null,
|
||
'is_ai_generated' => $validated['is_ai_generated'] ?? $build->is_ai_generated,
|
||
'ai_prompt' => $validated['ai_prompt'] ?? $build->ai_prompt,
|
||
]);
|
||
|
||
$build->components()->sync($validated['component_ids']);
|
||
});
|
||
|
||
return response()->json([
|
||
'message' => 'Сборка обновлена.',
|
||
'build' => $build->load('components'),
|
||
'compatibility' => $compatibility // опционально
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* @OA\Delete(
|
||
* path="/api/builds/{id}",
|
||
* summary="Удалить сборку",
|
||
* tags={"PC Builds"},
|
||
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
|
||
* @OA\Response(response=200, description="Сборка удалена"),
|
||
* @OA\Response(response=403, description="Запрещено")
|
||
* )
|
||
*/
|
||
public function destroy($id)
|
||
{
|
||
$build = PCBuild::findOrFail($id);
|
||
|
||
if ($build->user_id !== auth()->id()) {
|
||
return response()->json([
|
||
'message' => 'Вы не можете удалить эту сборку.'
|
||
], 403);
|
||
}
|
||
|
||
$build->delete();
|
||
|
||
return response()->json([
|
||
'message' => 'Сборка удалена.'
|
||
]);
|
||
}
|
||
} |