<?php
namespace App\Util;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface as TI;
class VaciFacilController extends AbstractController
{
public const TEMPLATE_BASE = "base.html.twig";
public const TEMPLATE_BLANK = "util/blank.html.twig";
public const TEMPLATE_GENERAL = "general";
public const TEMPLATE_HELP = "help";
public TI $translator;
public function __construct(TI $translator)
{
$this->translator = $translator;
}
protected function blank(): Response
{
return $this->render(self::TEMPLATE_BLANK, $this->getTemplateParameters());
}
/**
* Check whether the form is submitted and so if it is valid. If so, return the form data, otherwise return
* a redirect response to the same route altering the event to IntranetController::EVENT_BACK
* @param FormInterface $form
* @param Request $request
* @return mixed
*/
protected function checkForm(FormInterface $form, Request $request): mixed
{
// Inspects the given request for any submitted form
$form->handleRequest($request);
// Verify if the form is submitted and if is valid
if ($form->isSubmitted() && $form->isValid()) {
// Return the form data
return $form->getData();
} else {
// Add the form errors to the flash bag
foreach ($form->getErrors() as $error) { $this->addFlash("danger", $error->getMessage()); }
// Goes through the form fields
foreach ($form->all() as $child) {
// Check whether the child is valid
if ($child->isSubmitted() && !$child->isValid()) {
// Goes through the errors
foreach ($child->getErrors() as $item) {
// Add the error message to the flash bag
$this->addFlash("danger", "{$child->getName()}: {$item->getMessage()}");
}
}
}
// Get the route name
$route = $request->get("_route");
// Get the route parameters
$param = $request->get("_route_params");
// Since we call this when except that the form is submitted, you assume that the form is invalid
return $this->redirectToRoute($route, $param);
}
}
/**
* Used to optimize the code in the controller.
*
* When is a normal GET request, it creates the form without the data (because it won't be in the session) and the
* options' parameter need to be informed
*
* When is a redirect GET request, it creates the form getting data and options form the session and doesn't matter
* whether there's data or not
*
* When is POST request, we expected that is a submission, so it creates the form using the options from
* the session. After, it checks the form. If the form is valid, it will get the form data into the data parameter
* end will return the form. Otherwise, it will return a redirect response
*
* @param string $formClass an AbstractType object class used the creat the form
* @param Request $request used to get the session and process the form
* @param ?array $options used to create the form object
* @param ?array $data will be used in the controller when the form is processed
* @param mixed $obj when informed, use it instead of the session data
* @param ?string $keyAux used the get the auxiliary data in the controller
* @return ?FormInterface
*/
protected function defaultForm(string $formClass, Request $request, array &$options=null, array &$data=null, mixed $obj=null, string &$keyAux=null): ?FormInterface
{
// When the form is submitted or when the user click in the back button the options will be null
$nullOptions = is_null($options);
// Check if is a post request
$isPost = $request->getMethod() == "POST";
// Get the menu link
$menu = $request->get("menu");
// Get the names of the form and parent menu
$name = $formClass::NAME;
// Define the session keys for the form data and the options
list($keyData, $keyOptions, $keyAux) = ["$menu-$name-data", "$menu-$name-options", "$menu-$name-aux"];
// Get the session
$session = $request->getSession();
// When the options are informed they should be saved in the session, otherwise they should be in it
$nullOptions ? $options = $session->get($keyOptions) : $session->set($keyOptions, $options);
// Create the form object
$form = $this->createForm($formClass, $obj, $options);
// We want to process the form when it is submitted
if ($isPost && $nullOptions) {
// When the form is submitted and valid, the check function returns it data, otherwise return a response
if (($data = $this->checkForm($form, $request)) instanceof Response) { return null; }
// Save the form data in the session because it can be used later on
$session->set($keyData, $data);
}
// Return the form object that will be used in a template
return $form;
}
protected function defaultHandler(Request $request): Response
{
$menu = $request->get("menu");
$item = $request->get("item");
$action = $request->get("action");
$method = $request->getMethod();
$handler = "{$item}_{$action}_$method";
if (method_exists($this, $handler)) {
return $this->$handler($request, [
"menu" => $menu,
"item" => $item,
"action" => $action
]);
} else {
$this->addFlash("danger", "danger.0x001");
return $this->blank();
}
}
/**
* It groups the actions performed every time that a form is created
* @param Request $request used to generate the form action
* @param array $routeParam additional parameters to generate the form action (optional)
* @param array $data will be merged with the default options (optional)
* @param array $attr will be merged with the default attributes (optional)
* @return array the options used to create a form
*/
protected function getFormOptions(Request $request, array $routeParam=[], array $data=[], array $attr=[]): array
{
// Get the menu
$menu = $request->get("menu");
// Get the request parameters
$params = $request->get("_route_params");
// If any, merge the route parameters with the informed ones
if (!empty($routeParam)) { $params = array_merge($params, $routeParam); }
// Used by the JS script when sending AJAX requests
$controls = [
"menu" => (string) $menu,
"item" => (string) $request->get("item"),
"action" => (string) $request->get("action")
];
// Define the default options using the menu as the route name
$defaults = [
"action" => $this->generateUrl($menu, $params),
"attr" => array_merge(["data-controls" => json_encode($controls)], $attr)
];
// Set the user, used the fill some fields when loading the form
$defaults["vaciFacil_user"] = $this->getUser();
// Return the default options to create a form
return array_merge($defaults, $data);
}
/**
* Generates the template path adding the default template extension (".html.twig")
* @param string $templateName the template name without it extension
* @param array $templatePath the subdirectories of the template path
* @return string the relative path of the template
*/
protected function getTemplate(string $templateName, array $menu=null, array $templatePath=[]): string
{
if ($menu && empty($templatePath)) {
// Add the menu link to the path
$templatePath[] = $menu["menu"];
} else if (empty($templatePath)) {
// Add the "util" directory to the path
$templatePath[] = self::TEMPLATE_BLANK;
}
// Add the default extension to the template name
$templateName .= ".html.twig";
// Add the template name to the path
$templatePath[] = $templateName;
// Return the template full path
return implode("/", $templatePath);
}
protected function getTemplateParameters(... $vars): array
{
$result = ["meta" => [
"env" => "dev",
"locale" => $this->getParameter("locales")[0],
"menu" => $this->getParameter("menu")
]];
foreach ($vars as $value) {
if ($value instanceof FormInterface) { $result["form"] = $value->createView(); }
if (is_array($value)) { $result = array_merge($result, $value); }
}
return $result;
}
}