<?php
namespace App\Controller;
use App\Entity\EquipmentSet;
use App\Entity\Organization;
use App\Entity\Project;
use App\Form\EquipmentSetType;
use App\Form\ProjectIntroType;
use App\Service\ProjectService;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class ProjectController extends AbstractController
{
#[Route('/new-project/{id}', name: 'new_project')]
public function index(Request $request, ManagerRegistry $managerRegistry, Organization $organization): Response
{
$project = new Project($organization);
$form = $this->createForm(ProjectIntroType::class, $project, ['action' => $this->generateUrl('new_project', ['id' => $organization->getId()]), 'method' => 'POST']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$managerRegistry->getManager()->persist($project);
$managerRegistry->getManager()->flush();
return $this->redirectToRoute('project_detail', ['uuid' => $project->getUuid(), '_locale' => $request->getLocale()]);
}
return $this->renderForm('project/index.html.twig', [
'form' => $form,
'organization' => $organization,
]);
}
#[Route('/project/detail/{uuid}/remove/{id}', name: 'project_detail_remove_equipment_set')]
#[ParamConverter('project', class: Project::class, options: ['mapping' => ['uuid' => 'uuid']])]
#[ParamConverter('equipmentSet', class: EquipmentSet::class, options: ['mapping' => ['id' => 'id']])]
public function removeEquipmentSet(Project $project, EquipmentSet $equipmentSet, EntityManagerInterface $entityManager): Response
{
if ($equipmentSet->getProject() !== $project) {
$this->addFlash('error', 'trying to remove an invalid equipment set');
return $this->redirectToRoute('project_detail');
}
$entityManager->remove($equipmentSet);
$entityManager->flush();
return $this->redirectToRoute('project_detail', ['uuid' => $project->getUuid()]);
}
#[Route('/project/detail/{uuid}', name: 'project_detail')]
public function detail(Project $project, Request $request, EntityManagerInterface $entityManager, ProjectService $projectService, Response $response = null): Response
{
// I will create dynamically multiple forms on the same page (one for each equipmentSet, plus one for creating a new equipmentSet).
// I can't use neither $this->renderForm, nor $this->createForm because it is designed for a fixed list of forms, associated to different FormType (2 forms with the same FormType will have the same name, so we can't know which one have been submitted)
// So I do nearly the same thing as $this->renderForm + the same thing we usually do to treat a form, with adaptations to my custom situation
if (is_null($response)) {
$response = new Response();
}
// Create forms for each equipment set
$equipmentSets = $project->getEquipmentSets();
$equipmentSetForms = [];
$equipmentSetFormViews = [];
foreach ($equipmentSets as $k => $equipmentSet) {
// I do the same thing as $this->createForm, but with a name that will allow me to detect wich form is currently submitted
$equipmentSetForms[$k] = $this->container->get('form.factory')->createNamed('equipment_set_'.$k, EquipmentSetType::class, $equipmentSet);
$equipmentSetForms[$k]->handleRequest($request);
// I do the same thing as $this->renderForm, but on each included form
$equipmentSetFormViews[$k] = $equipmentSetForms[$k]->createView();
}
// Create form for new equipment set
$newEquipmentSet = new EquipmentSet();
// Here I use $this->createForm, I know that this form only will have the standard name 'equipment_set'
$newEquipmentSetForm = $this->createForm(EquipmentSetType::class, $newEquipmentSet);
$newEquipmentSetForm->handleRequest($request);
// I do the same thing as $this->renderForm, but on each subform
$newEquipmentSetFormView = $newEquipmentSetForm->createView();
// Handle submission on the right for every form. I do the same thing as $this->renderForm, but here
if ($newEquipmentSetForm->isSubmitted()) {
if ($newEquipmentSetForm->isValid()) {
// As usual, I handle the request if this form is submitted and valid
/** @var EquipmentSet $newEquipmentSet */
$newEquipmentSet = $newEquipmentSetForm->getData();
$entityManager->persist($project);
$project->addEquipmentSet($newEquipmentSet);
$entityManager->flush();
// I redirect so that my new equipment set will now have a form, and a new newEquipmentSetForm will be created
return $this->redirectToRoute('project_detail', ['uuid' => $project->getUuid()]);
} else {
// I do the same thing as $this->renderForm. The code 422 will allow the form view to know that errors must be displayed on this form.
// (otherwise the errors are well computed by Symfony, they appear in the profiler, but they are not displayed by the FormView)
$response->setStatusCode(422);
}
} else {
// approximately the same on each existing equipmentSetForm
foreach ($equipmentSetForms as $equipmentSetForm) {
if ($equipmentSetForm->isSubmitted()) {
if ($equipmentSetForm->isValid()) {
// As usual
$equipmentSet = $equipmentSetForm->getData();
$entityManager->persist($equipmentSet);
$entityManager->flush();
// I also redirect even if it is not actually mandatory, just to keep consistency with the creation process
return $this->redirectToRoute('project_detail', ['uuid' => $project->getUuid()]);
} else {
// make FormView know that there are errors on the form
$response->setStatusCode(422);
}
break;
}
}
}
// Some values of the project are not stored in database, but computed on the fly
$projectService->calculate($project);
return $this->render('project/detail.html.twig', [
'project' => $project,
'equipmentSets' => $equipmentSets,
'equipmentSetForms' => $equipmentSetFormViews,
'newEquipmentSetForm' => $newEquipmentSetFormView,
], $response);
}
}