[英]Symfony 2 - keeping the code DRY - FOSRestBundle
我目前正在使用Symfony2創建(並學習如何)REST API。 我正在使用FOSRestBundle,並使用以下命令創建了一個“ ApiControllerBase.php”:
<?php
namespace Utopya\UtopyaBundle\Controller;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\View;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class ApiControllerBase
*
* @package Utopya\UtopyaBundle\Controller
*/
abstract class ApiControllerBase extends FOSRestController
{
/**
* @param string $entityName
* @param string $entityClass
*
* @return array
* @throws NotFoundHttpException
*/
protected function getObjects($entityName, $entityClass)
{
$dataRepository = $this->container->get("doctrine")->getRepository($entityClass);
$entityName = $entityName."s";
$data = $dataRepository->findAll();
foreach ($data as $object) {
if (!$object instanceof $entityClass) {
throw new NotFoundHttpException("$entityName not found");
}
}
return array($entityName => $data);
}
/**
* @param string $entityName
* @param string $entityClass
* @param integer $id
*
* @return array
* @throws NotFoundHttpException
*/
protected function getObject($entityName, $entityClass, $id)
{
$dataRepository = $this->container->get("doctrine")->getRepository($entityClass);
$data = $dataRepository->find($id);
if (!$data instanceof $entityClass) {
throw new NotFoundHttpException("$entityName not found");
}
return array($entityClass => $data);
}
/**
* @param FormTypeInterface $objectForm
* @param mixed $object
* @param string $route
*
* @return Response
*/
protected function processForm(FormTypeInterface $objectForm, $object, $route)
{
$statusCode = $object->getId() ? 204 : 201;
$em = $this->getDoctrine()->getManager();
$form = $this->createForm($objectForm, $object);
$form->submit($this->container->get('request_stack')->getCurrentRequest());
if ($form->isValid()) {
$em->persist($object);
$em->flush();
$response = new Response();
$response->setStatusCode($statusCode);
// set the `Location` header only when creating new resources
if (201 === $statusCode) {
$response->headers->set('Location',
$this->generateUrl(
$route, array('id' => $object->getId(), '_format' => 'json'),
true // absolute
)
);
}
return $response;
}
return View::create($form, 400);
}
}
這處理獲取一個具有給定id的對象,所有對象並處理表單。 但是要使用它,我必須根據需要創建盡可能多的控制器。 例如:GameController。
<?php
namespace Utopya\UtopyaBundle\Controller;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Utopya\UtopyaBundle\Entity\Game;
use Utopya\UtopyaBundle\Form\GameType;
/**
* Class GameController
*
* @package Utopya\UtopyaBundle\Controller
*/
class GameController extends ApiControllerBase
{
private $entityName = "Game";
private $entityClass = 'Utopya\UtopyaBundle\Entity\Game';
/**
* @Rest\View()
*/
public function getGamesAction()
{
return $this->getObjects($this->entityName, $this->entityClass);
}
/**
* @param int $id
*
* @return array
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* @Rest\View()
*/
public function getGameAction($id)
{
return $this->getObject($this->entityName, $this->entityClass, $id);
}
/**
* @return mixed
*/
public function postGameAction()
{
return $this->processForm(new GameType(), new Game(), "get_game");
}
}
聽起來對我來說還算不錯,但是有一個主要問題:如果我想創建另一個控制器(例如,服務器,用戶或角色),我將不得不執行相同的過程,而且我也不想這樣做。邏輯相同。
另一個“也許”問題可能是我的$ entityName和$ entityClass。
任何想法還是我可以使它更好?
謝謝 !
=====編輯1 =====
我想我下定了決心。 對於那些基本的控制器。 我希望能夠“配置”而不是“重復”。
通過示例,我可以使用以下命令在config.yml中創建一個新節點:
#config.yml
mynode:
game:
entity: 'Utopya\UtopyaBundle\Entity\Game'
這是一個非常基本的示例,但是是否可以通過3種方法(getGame,getGames,postGame)將其轉換為我的GameController?
如果我真的可以用這種方法實現,我只是想要一些線索,如果可以,用什么組件可以實現? (配置,路由器等)
如果沒有,我該怎么辦? :)
謝謝 !
我想在這里展示我的方法。
我已經為API創建了基本控制器,並且堅持使用FOSRest
的rest
路由類型生成的路由 。 因此,控制器看起來像這樣:
<?php
use FOS\RestBundle\Controller\Annotations\View;
use \Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Psr\Log\LoggerInterface;
use Symfony\Component\Form\FormFactoryInterface,
Symfony\Bridge\Doctrine\RegistryInterface,
Symfony\Component\Security\Core\SecurityContextInterface,
Doctrine\Common\Persistence\ObjectRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
abstract class AbstractRestController
{
/**
* @var \Symfony\Component\Form\FormFactoryInterface
*/
protected $formFactory;
/**
* @var string
*/
protected $formType;
/**
* @var string
*/
protected $entityClass;
/**
* @var SecurityContextInterface
*/
protected $securityContext;
/**
* @var RegistryInterface
*/
protected $doctrine;
/**
* @var EventDispatcherInterface
*/
protected $dispatcher;
/**
* @param FormFactoryInterface $formFactory
* @param RegistryInterface $doctrine
* @param SecurityContextInterface $securityContext
* @param LoggerInterface $logger
*/
public function __construct(
FormFactoryInterface $formFactory,
RegistryInterface $doctrine,
SecurityContextInterface $securityContext,
EventDispatcherInterface $dispatcher
)
{
$this->formFactory = $formFactory;
$this->doctrine = $doctrine;
$this->securityContext = $securityContext;
$this->dispatcher = $dispatcher;
}
/**
* @param string $formType
*/
public function setFormType($formType)
{
$this->formType = $formType;
}
/**
* @param string $entityClass
*/
public function setEntityClass($entityClass)
{
$this->entityClass = $entityClass;
}
/**
* @param null $data
* @param array $options
*
* @return \Symfony\Component\Form\FormInterface
*/
public function createForm($data = null, $options = array())
{
return $this->formFactory->create(new $this->formType(), $data, $options);
}
/**
* @return RegistryInterface
*/
public function getDoctrine()
{
return $this->doctrine;
}
/**
* @return \Doctrine\ORM\EntityRepository
*/
public function getRepository()
{
return $this->doctrine->getRepository($this->entityClass);
}
/**
* @param Request $request
*
* @View(serializerGroups={"list"}, serializerEnableMaxDepthChecks=true)
*/
public function cgetAction(Request $request)
{
$this->logger->log('DEBUG', 'CGET ' . $this->entityClass);
$offset = null;
$limit = null;
if ($range = $request->headers->get('Range')) {
list($offset, $limit) = explode(',', $range);
}
return $this->getRepository()->findBy(
[],
null,
$limit,
$offset
);
}
/**
* @param int $id
*
* @return object
*
* @View(serializerGroups={"show"}, serializerEnableMaxDepthChecks=true)
*/
public function getAction($id)
{
$this->logger->log('DEBUG', 'GET ' . $this->entityClass);
$object = $this->getRepository()->find($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('%s#%s not found', $this->entityClass, $id));
}
return $object;
}
/**
* @param Request $request
*
* @return \Symfony\Component\Form\Form|\Symfony\Component\Form\FormInterface
*
* @View()
*/
public function postAction(Request $request)
{
$object = new $this->entityClass();
$form = $this->createForm($object);
$form->submit($request);
if ($form->isValid()) {
$this->doctrine->getManager()->persist($object);
$this->doctrine->getManager()->flush($object);
return $object;
}
return $form;
}
/**
* @param Request $request
* @param int $id
*
* @return \Symfony\Component\Form\FormInterface
*
* @View()
*/
public function putAction(Request $request, $id)
{
$object = $this->getRepository()->find($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('%s#%s not found', $this->entityClass, $id));
}
$form = $this->createForm($object);
$form->submit($request);
if ($form->isValid()) {
$this->doctrine->getManager()->persist($object);
$this->doctrine->getManager()->flush($object);
return $object;
}
return $form;
}
/**
* @param Request $request
* @param $id
*
* @View()
*
* @return object|\Symfony\Component\Form\FormInterface
*/
public function patchAction(Request $request, $id)
{
$this->logger->log('DEBUG', 'PATCH ' . $this->entityClass);
$object = $this->getRepository()->find($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('%s#%s not found', $this->entityClass, $id));
}
$form = $this->createForm($object);
$form->submit($request, false);
if ($form->isValid()) {
$this->doctrine->getManager()->persist($object);
$this->doctrine->getManager()->flush($object);
return $object;
}
return $form;
}
/**
* @param int $id
*
* @return array
*
* @View()
*/
public function deleteAction($id)
{
$this->logger->log('DEBUG', 'DELETE ' . $this->entityClass);
$object = $this->getRepository()->find($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('%s#%s not found', $this->entityClass, $id));
}
$this->doctrine->getManager()->remove($object);
$this->doctrine->getManager()->flush($object);
return ['success' => true];
}
}
它具有用於大多數RESTful操作的方法。 接下來,當我想為實體實施CRUD時,這就是我要做的:
抽象控制器在DI中注冊為抽象服務:
my_api.abstract_controller:
class: AbstractRestController
abstract: true
arguments:
- @form.factory
- @doctrine
- @security.context
- @logger
- @event_dispatcher
接下來,當我為新實體實現CRUD時,將為其創建一個空類和一個服務定義:
class SettingController extends AbstractRestController implements ClassResourceInterface {}
請注意,該類實現ClassResourceInterface
。 這對於rest
路由工作很有必要。
這是此控制器的服務聲明:
api.settings.controller.class: MyBundle\Controller\SettingController
api.settings.form.class: MyBundle\Form\SettingType
my_api.settings.controller:
class: %api.settings.controller.class%
parent: my_api.abstract_controller
calls:
- [ setEntityClass, [ MyBundle\Entity\Setting ] ]
- [ setFormType, [ %my_api.settings.form.class% ] ]
然后,我只將控制器作為FOSRestBundle文檔的狀態包含在routing.yml
中,就完成了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.