# src/Acme/DemoBundle/Resources/config/routing.yml acme_demo_user_all: pattern: /users defaults: { _controller: AcmeDemoBundle:User:all, _format: ~ } requirements: _method: GET acme_demo_user_get: pattern: /users/{id} defaults: { _controller: AcmeDemoBundle:User:get, _format: ~ } requirements: _method: GET id: "\d+"
<?php namespace Acme\DemoBundle\Controller; use Acme\DemoBundle\Model\User; use Acme\DemoBundle\Model\UserQuery; use FOS\RestBundle\Controller\Annotations as Rest; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class UserController { /** * @Rest\View */ public function allAction() { $users = UserQuery::create()->find(); return array('users' => $users); } /** * @Rest\View */ public function getAction($id) { $user = UserQuery::create()->findPk($id); if (!$user instanceof User) { throw new NotFoundHttpException('User not found'); } return array('user' => $user); } }
# In Propel, the most part of the code is located in base classes # src/Acme/DemoBundle/Resources/config/serializer/Model.om.BaseUser.yml Acme\DemoBundle\Model\om\BaseUser: exclusion_policy: ALL properties: id: expose: true username: expose: true email: expose: true
{ "user": { "id": 999, "username": "xxxx", "email": "xxxx@example.org" } }
php app/console propel:form:generate @AcmeDemoBundle User
<?php namespace Acme\DemoBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; class UserType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('username'); $builder->add('email', 'email'); $builder->add('password', 'password'); } /** * {@inheritdoc} */ public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'Acme\DemoBundle\Model\User', 'csrf_protection' => false, )); } /** * {@inheritdoc} */ public function getName() { return 'user'; } }
# src/Acme/DemoBundle/Resources/config/validation.yml Acme\DemoBundle\Model\User: getters: username: - NotBlank: email: - NotBlank: - Email: password: - NotBlank:
<?php // ... public function newAction() { return $this->processForm(new User()); }
// ... private function processForm(User $user) { $statusCode = $user->isNew() ? 201 : 204; $form = $this->createForm(new UserType(), $user); $form->bind($this->getRequest()); if ($form->isValid()) { $user->save(); $response = new Response(); $response->setStatusCode($statusCode); $response->headers->set('Location', $this->generateUrl( 'acme_demo_user_get', array('id' => $user->getId()), true // absolute ) ); return $response; } return View::create($form, 400); }
{ "children": { "username": { "errors": [ "This value should not be blank." ] } } }
{ "user": { "username": "foo", "email": "foo@example.org", "password": "hahaha" } }
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"user":{"username":"foo", "email": "foo@example.org", "password": "hahaha"}}' http://example.com/users
Location: http://example.com/users/999
acme_demo_user_new: pattern: /users defaults: { _controller: AcmeDemoBundle:User:new, _format: ~ } requirements: _method: POST
<?php // ... public function editAction(User $user) { return $this->processForm($user); }
acme_demo_user_edit: pattern: /users/{id} defaults: { _controller: AcmeDemoBundle:User:edit, _format: ~ } requirements: _method: PUT
acme_demo_user_delete: pattern: /users/{id} defaults: { _controller: AcmeDemoBundle:User:remove, _format: ~ } requirements: _method: DELETE
<?php // ... /** * @Rest\View(statusCode=204) */ public function removeAction(User $user) { $user->delete(); }
acme_demo_user_get_friends: pattern: /users/{id}/friends defaults: { _controller: AcmeDemoBundle:User:getFriends, _format: ~ } requirements: _method: GET
<?php // ... public function getFriendsAction(User $user) { return array('friends' => $user->getFriends()); }
The LINK method establishes one or more links between an existing resource specified in the Request-URI and other existing resources.
LINK /users/1 Link: <http://example.com/users/2>; rel="friend" Link: <http://example.com/users/3>; rel="friend"
<?php namespace Acme\DemoBundle\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; use Symfony\Component\HttpFoundation\Request; class LinkRequestListener { /** * @var ControllerResolverInterface */ private $resolver; private $urlMatcher; /** * @param ControllerResolverInterface $controllerResolver The 'controller_resolver' service * @param UrlMatcherInterface $urlMatcher The 'router' service */ public function __construct(ControllerResolverInterface $controllerResolver, UrlMatcherInterface $urlMatcher) { $this->resolver = $controllerResolver; $this->urlMatcher = $urlMatcher; } public function onKernelRequest(GetResponseEvent $event) { if (!$event->getRequest()->headers->has('link')) { return; } $links = array(); $header = $event->getRequest()->headers->get('link'); /* * , * . * * Link * http://tools.ietf.org/html/rfc2068#section-19.6.2.4 */ while (preg_match('/^((?:[^"]|"[^"]*")*?),/', $header, $matches)) { $header = trim(substr($header, strlen($matches[0]))); $links[] = $matches[1]; } if ($header) { $links[] = $header; } $requestMethod = $this->urlMatcher->getContext()->getMethod(); // GET // , (LINK/UNLINK) $this->urlMatcher->getContext()->setMethod('GET'); // $stubRequest = new Request(); foreach ($links as $idx => $link) { $linkParams = explode(';', trim($link)); $resource = array_shift($linkParams); $resource = preg_replace('/<|>/', '', $resource); try { $route = $this->urlMatcher->match($resource); } catch (\Exception $e) { // // Link continue; } $stubRequest->attributes->replace($route); if (false === $controller = $this->resolver->getController($stubRequest)) { continue; } $arguments = $this->resolver->getArguments($stubRequest, $controller); try { $result = call_user_func_array($controller, $arguments); // if (!is_array($result)) { continue; } // $links[$idx] = current($result); } catch (\Exception $e) { continue; } } $event->getRequest()->attributes->set('link', $links); $this->urlMatcher->getContext()->setMethod($requestMethod); } }
acme_demo_user_link: pattern: /users/{id} defaults: { _controller: AcmeDemoBundle:User:link, _format: ~ } requirements: _method: LINK
<?php // ... /** * @Rest\View(statusCode=204) */ public function linkAction(User $user, Request $request) { if (!$request->attributes->has('link')) { throw new HttpException(400); } foreach ($request->headers->get('Link') as $u) { if (!$u instanceof User) { throw new NotFoundHttpException('Invalid resource'); } if ($user->hasFriend($u)) { throw new HttpException(409, 'Users are already friends'); } $user->addFriend($u); } $user->save(); }
acme_demo_user_patch: pattern: /users/{id} defaults: { _controller: AcmeDemoBundle:User:patch, _format: ~ } requirements: _method: PATCH
<?php $parameters = array(); foreach ($request->request->all() as $k => $v) { // if (in_array($k, array('email'))) { $parameters[$k] = $v; } }
<?php // .... public function patchAction(User $user, Request $request) { $parameters = array(); foreach ($request->request->all() as $k => $v) { // whitelist if (in_array($k, array('email'))) { $parameters[$k] = $v; } } if (0 === count($parameters)) { return View::create( array('errors' => array('Invalid parameters.')), 400 ); } $user->fromArray($parameters); $errors = $this->get('validator')->validate($user); if (0 < count($errors)) { return View::create(array('errors' => $errors), 400); } $user->save(); $response = new Response(); $response->setStatusCode(204); $response->headers->set('Location', $this->generateUrl( 'acme_demo_user_get', array('id' => $user->getId()), true // absolute ) ); return $response; }
<user> <id>999</id> <username>xxxx</username> <email>xxxx@example.org</email> </user>
<user> <id>999</id> <username>xxxx</username> <email>xxxx@example.org</email> <link href="http://example.com/users/999" rel="self" /> </user>
<users> <user> <id>999</id> <username>xxxx</username> <email>xxxx@example.org</email> <link href="http://example.com/users/999" rel="self" /> <link href="http://example.com/users/999/friends" rel="friends" /> </user> <user> <id>123</id> <username>foobar</username> <email>foobar@example.org</email> <link href="http://example.com/users/123" rel="self" /> <link href="http://example.com/users/123/friends" rel="friends" /> </user> <link href="http://example.com/users?page=1" rel="prev" /> <link href="http://example.com/users?page=2" rel="self" /> <link href="http://example.com/users?page=3" rel="next" /> </users>
Content-Type: application/vnd.yourname.something+xml
<user> <id>999</id> <username>xxxx</username> <email>xxxx@example.org</email> <link href="http://example.com/users/999" rel="self" /> <link rel="friends" type="application/vnd.acme.user+xml" href="http://example.com/users/999/friends" /> </user>
/api/v1/users
application/vnd.acme.user-v1+xml
application/vnd.acme.user+xml;v=1
$client = static::createClient(); $crawler = $client->request('GET', '/users'); $response = $this->client->getResponse(); $this->assertJsonResponse($response, 200);
<?php // ... protected function assertJsonResponse($response, $statusCode = 200) { $this->assertEquals( $statusCode, $response->getStatusCode(), $response->getContent() ); $this->assertTrue( $response->headers->contains('Content-Type', 'application/json'), $response->headers ); }
Source: https://habr.com/ru/post/148951/
All Articles