鉴于以下Category
实体......
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* @ORM\Table(name="category", uniqueConstraints = @ORM\UniqueConstraint(name="unique_categoryName", columns={"name"})})
* @ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=64)
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="description", type="string", length=256, nullable=true)
*/
private $description;
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Subcategory", mappedBy="category", cascade={"remove"})
* @ORM\OrderBy({"name" = "ASC"})
*/
private $subcategories;
...
}
...以及以下Subcategory
实体:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Subcategory
*
* @ORM\Table(name="subcategory")
* @ORM\Entity(repositoryClass="AppBundle\Repository\SubcategoryRepository")
*/
class Subcategory
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=64)
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="description", type="string", length=256, nullable=true)
*/
private $description;
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="subcategories")
*/
private $category;
...
}
我正在使用https://github.com/voryx/restgeneratorbundle
来生成REST控制器......下面是我的src/AppBundle/Form/SubcategoryType
看起来如何(src/AppBundle/Form/CategoryType
非常相似):
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class SucategoryType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('description')
->add('category', 'voryx_entity', array('class' => 'AppBundle\Entity\Category'))
;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Sucategory'
));
}
/**
* @return string
*/
public function getName()
{
return 'appbundle_subcategory';
}
}
最后这是我的src/AppBundle/Controller/CategoryRESTController
:
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Category;
use AppBundle\Form\CategoryType;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\RouteResource;
use FOS\RestBundle\Controller\Annotations\View;
use FOS\RestBundle\Request\ParamFetcherInterface;
use FOS\RestBundle\Util\Codes;
use FOS\RestBundle\View\View as FOSView;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Voryx\RESTGeneratorBundle\Controller\VoryxController;
/**
* Category controller.
* @RouteResource("Category")
*/
class CategoryRESTController extends VoryxController
{
/**
* Get a Category entity
*
* @View(serializerEnableMaxDepthChecks=true)
*
* @return Response
*
*/
public function getAction(Category $entity)
{
return $entity;
}
/**
* Get all Category entities.
*
* @View(serializerEnableMaxDepthChecks=true)
*
* @param ParamFetcherInterface $paramFetcher
*
* @return Response
*
* @QueryParam(name="offset", requirements="\d+", nullable=true, description="Offset from which to start listing notes.")
* @QueryParam(name="limit", requirements="\d+", default="20", description="How many notes to return.")
* @QueryParam(name="order_by", nullable=true, array=true, description="Order by fields. Must be an array ie. &order_by[name]=ASC&order_by[description]=DESC")
* @QueryParam(name="filters", nullable=true, array=true, description="Filter by fields. Must be an array ie. &filters[id]=3")
*/
public function cgetAction(ParamFetcherInterface $paramFetcher)
{
try {
$offset = $paramFetcher->get('offset');
$limit = $paramFetcher->get('limit');
$order_by = $paramFetcher->get('order_by');
$filters = !is_null($paramFetcher->get('filters')) ? $paramFetcher->get('filters') : array();
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('AppBundle:Category')->findBy($filters, $order_by, $limit, $offset);
if ($entities) {
return $entities;
}
return FOSView::create('Not Found', Codes::HTTP_NO_CONTENT);
} catch (\Exception $e) {
return FOSView::create($e->getMessage(), Codes::HTTP_INTERNAL_SERVER_ERROR);
}
}
/**
* Create a Category entity.
*
* @View(statusCode=201, serializerEnableMaxDepthChecks=true)
*
* @param Request $request
*
* @return Response
*
*/
public function postAction(Request $request)
{
$entity = new Category();
$form = $this->createForm(new CategoryType(), $entity, array("method" => $request->getMethod()));
$this->removeExtraFields($request, $form);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $entity;
}
return FOSView::create(array('errors' => $form->getErrors()), Codes::HTTP_INTERNAL_SERVER_ERROR);
}
/**
* Update a Category entity.
*
* @View(serializerEnableMaxDepthChecks=true)
*
* @param Request $request
* @param $entity
*
* @return Response
*/
public function putAction(Request $request, Category $entity)
{
try {
$em = $this->getDoctrine()->getManager();
$request->setMethod('PATCH'); //Treat all PUTs as PATCH
$form = $this->createForm(new CategoryType(), $entity, array("method" => $request->getMethod()));
$this->removeExtraFields($request, $form);
$form->handleRequest($request);
if ($form->isValid()) {
$em->flush();
return $entity;
}
return FOSView::create(array('errors' => $form->getErrors()), Codes::HTTP_INTERNAL_SERVER_ERROR);
} catch (\Exception $e) {
return FOSView::create($e->getMessage(), Codes::HTTP_INTERNAL_SERVER_ERROR);
}
}
/**
* Partial Update to a Category entity.
*
* @View(serializerEnableMaxDepthChecks=true)
*
* @param Request $request
* @param $entity
*
* @return Response
*/
public function patchAction(Request $request, Category $entity)
{
return $this->putAction($request, $entity);
}
/**
* Delete a Category entity.
*
* @View(statusCode=204)
*
* @param Request $request
* @param $entity
*
* @return Response
*/
public function deleteAction(Request $request, Category $entity)
{
try {
$em = $this->getDoctrine()->getManager();
$em->remove($entity);
$em->flush();
return null;
} catch (\Exception $e) {
return FOSView::create($e->getMessage(), Codes::HTTP_INTERNAL_SERVER_ERROR);
}
}
}
发布添加像这样的单个类别的请求非常有效:
curl -i -H "Content-Type: application/json" -X POST -d '{"name" : "Sport", "description" : "Sport category"}' http://localhost:8000/api/categories
......结果如下:
+----+-------+---------------------------+
| id | name | description |
+----+-------+---------------------------+
| 1 | Sport | Sport category |
+----+-------+---------------------------+
但是,如何发布将子类别添加到上面创建的类别的请求?想法是添加这样的子类别:
curl -i -H "Content-Type: application/json" -X POST -d '{"name" : "Football", "description" : "Groups ranks about football"}' http://localhost:8000/api/categories/1/subcategories
答案 0 :(得分:4)
是的,创建类别子类别资源的POST请求将是完全可以的。
我也认为(基于此实体的外观)您不需要SubcategoryType
。因为它与CategoryType
相同。
相反,您可以查看两个实体Gedmo Tree extension
:https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/tree.md并将所有实体保留在一个实体上。