Извините, если этот вопрос слишком запутан, но есть ли общий способ обработки запроса формы в Symfony? (Я использую SF 4).
На данный момент у меня в контроллере есть логика:
$formBooking = $this->createForm(BookingType::class);
$formBooking->handleRequest($request);
if ($formBooking->isSubmitted() && $formBooking->isValid()) {
// perform actions ...
У меня есть несколько форм на одной странице, поэтому мой контроллер становится все больше и больше.
Я хотел создать новую папку, например Действие, и поместить сюда логическую.
И сделайте в моем контроллере:
$formBooking = $this->createForm(BookingType::class);
// $bookingAction = new App\Action\BookingAction
$bookingAction->handleRequest($formBooking, $request);
Я просто хочу знать, есть ли для этого «официальный» способ?
Да, я перейду к действию, я не хочу смешивать с сервисами, поскольку действие предназначено только для обработки форм. Для меня более логично оставить контроллеры на верхнем уровне.
Тщательно продумайте первый комментарий. Ограничение одного действия на контроллер решит проблему выхода контроллеров из-под контроля. И устраните предлагаемое вами довольно неудобное разделение BookingAction.
К сведению, почему это разделение неудобно? SymfonyDoc говорит, что лучше отправлять запрос формы в том же методе / контроллере. Лучше создать новый контроллер и установить действие формы на этот контроллер? Спасибо.
Ваш первый код - это «стандартный» способ обработки форм. Раздел, который вы пометили «// выполнить действия», - это то, что вы могли бы подумать о переходе на другую службу. Предполагая, что это сложнее, чем просто сохранить объект бронирования и перенаправить. Служба не должна знать форму или запрос. Но опять же, если ваша основная цель - сократить код контроллера, то одно действие на контроллер - это легкая отправная точка.




Вы можете создать абстрактный «BaseController» и унаследовать свой другой контроллер. Я не думаю, что это «официальный» способ, но он кажется правильным.
В моем примере я установил диспетчер сущностей, фабрику форм и маршрутизацию как службы. Кроме того, он называется BaseManager, так как вся моя логика находится в файле менеджера, в то время как у моего контроллера нет кода (это просто вызов моего менеджера, за исключением особых случаев)
Для этого просто обратитесь к своему сервису, и пусть ваш контроллер будет главным, но простым и понятным.
## Controller##
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Category;
use AppBundle\Form\CategoryType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
/**
* @Route("/admin/category")
*/
class CategoryController extends Controller
{
/**
* @Template()
* @Route("/", name = "category_index")
* @return array
*/
public function indexAction()
{
$categories = $this->get('app.category.manager')->find();
return array('categories' => $categories);
}
/**
* @Template()
* @Route("/", name = "category_menu")
* @return array
*/
public function menuAction()
{
$categories = $this->getDoctrine()->getRepository('AppBundle:Category')->findAllOrdered("ASC");
return array('categories' => $categories);
}
/**
* @Template()
* @Route("/icones/glyficones", name = "category_icones_glyficones")
* @return array
*/
public function fontawesomeAction()
{
return array();
}
/**
* @Template()
* @Route("/icones/fontawesome", name = "category_icones_fontawesome")
* @return array
*/
public function glyficoneAction()
{
return array();
}
/**
* @Template()
* @Route("/new", name = "category_create")
* @param Request $request
* @return array
*/
public function newAction(Request $request)
{
return $this->get('app.category.manager')->save($request);
}
/**
* @Template()
* @Route("/{id}/edit", name = "category_edit")
* @param Request $request
* @param $id
* @return array
*/
public function editAction(Request $request, $id)
{
return $this->get('app.category.manager')->edit($request, $id);
}
/**
* @Template()
* @Route("/{id}/delete", name = "category_delete")
* @param Request $request
* @param $id
* @return array
*/
public function deleteAction(Request $request, $id)
{
return $this->get('app.category.manager')->delete($request, $id);
}
}
<?php
namespace AppBundle\Manager;
use AppBundle\Form\CategoryType;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
abstract class BaseManager
{
protected $em;
protected $formFactory;
protected $router;
/**
* CategoryManager constructor.
* @param $em
* @param $formFactory
* @param Router $router
*/
public function __construct($em, $formFactory, Router $router)
{
$this->em = $em;
$this->formFactory = $formFactory;
$this->router = $router;
}
/**
* @param $entity
*/
protected function persistAndFlush($entity)
{
$this->em->persist($entity);
$this->em->flush();
}
/**
* @param $entity
*/
protected function removeAndFlush($entity)
{
$this->em->remove($entity);
$this->em->flush();
}
/**
* @param Request $request
* @param Form $form
* @param $entity
* @param $path
* @return array|RedirectResponse
*/
protected function handleBaseForm(Request $request, Form $form, $entity, $path)
{
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->persistAndFlush($entity);
return new RedirectResponse($this->router->generate($path));
}
return array('form' => $form->createView());
}
/**
* @param $route
* @return RedirectResponse
*/
protected function redirect($route)
{
return new RedirectResponse($this->router->generate($route));
}
}
А вот пример, простой примитив из сущности "Категория".
<?php
namespace AppBundle\Manager;
use AppBundle\Entity\Category;
use AppBundle\Form\CategoryType;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Class CategoryManager
* @package AppBundle\Manager
*/
class CategoryManager extends BaseManager
{
/**
* CategoryManager constructor.
* @param $em
* @param $formFactory
* @param Router $router
*/
public function __construct($em, $formFactory, Router $router)
{
parent::__construct($em, $formFactory, $router);
}
/**
* @return mixed
*/
public function find()
{
return $this->em->getRepository('AppBundle:Category')->findAll();
}
/**
* @param Request $request
* @return array
*/
public function save(Request $request)
{
$category = new Category();
return $this->handleForm($request, $category);
}
/**
* @param Request $request
* @param $id
* @return array|RedirectResponse
*/
public function edit(Request $request, $id)
{
$category = $this->em->getRepository('AppBundle:Category')->find($id);
return $this->handleForm($request, $category);
}
/**
* @param Request $request
* @param $id
* @return RedirectResponse
*/
public function delete(Request $request, $id)
{
$category = $this->em->getRepository('AppBundle:Category')->find($id);
$this->persistAndFlush($category);
return $this->redirect('category_index');
}
/**
* @param Request $request
* @param Category $category
* @return array|RedirectResponse
*/
public function handleForm(Request $request, $category)
{
$form = $this->formFactory->create(CategoryType::class, $category);
return $this->handleBaseForm($request, $form, $category, "category_index");
}
}
На всякий случай вот мой файл services.yaml
services:
app.category.manager:
class: AppBundle\Manager\CategoryManager
arguments: [ '@doctrine.orm.entity_manager', '@form.factory', '@router' ]
fos_user.doctrine_registry:
alias: doctrine
Надеюсь, это поможет решить вашу проблему и получить более чистый код. Обратите внимание, что это личное решение, и, вероятно, есть решения получше. Но этот рабочий, который мне кажется чище, чем просто позволить контроллеру иметь всю логику.
У вас есть два способа разделить код: сначала создайте множество контроллеров на основе вашей бизнес-логики. во-вторых, перейти к обслуживанию вашей бизнес-логики, чтобы сохранить уровень верхнего уровня вашего контроллера.