Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added simple task crud tutorial #1545

Open
wants to merge 3 commits into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions Resources/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ Config reference
- :doc:`Annotations reference <annotations-reference>` for a reference on
the available configurations through annotations

Task CRUD tutorial
--------------------

The following tutorial shows how to handle forms in the "REST" like way

- :doc:`Task CRUD tutorial <task-crud-tutorial>`

Example applications
--------------------

Expand Down
336 changes: 336 additions & 0 deletions Resources/doc/task-crud-tutorial.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
Task CRUD tutorial
==================

Suppose that we have a fresh Symfony project with FOSRestBundle installed and configured in that way:

.. code-block:: yml
xabbuh marked this conversation as resolved.
Show resolved Hide resolved

// app/config/config.yml
fos_rest:
view:
view_response_listener: force # for always return View from FOSRestBundle Annotations
formats:
json: true
body_listener: true # for decoding our request to forms
routing_loader:
default_format: json
include_format: false # for remove ".json" suffix from all of our routes

A) Create Task entity
---------------------

For this tutorial we create Task entity with two simple fields ``name`` and ``completed``
xabbuh marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: php

// src/AppBundle/Entity/Task.php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* Task
*
* @ORM\Table(name="task")
*/
class Task
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;

/**
* @var boolean
*
* @ORM\Column(name="completed", type="boolean")
*/
private $completed;


/**
* Get id
*
* @return int
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would omit all the docblock comments. They imo do not add much value.

public function getId()
{
return $this->id;
}

/**
* Set name
*
* @param string $name
*
* @return Task
*/
public function setName($name)
{
$this->name = $name;

return $this;
}

/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}

/**
* Set code
*
* @param string $completed
*
* @return Task
*/
public function setCompleted($completed)
{
$this->completed = $completed;

return $this;
}

/**
* Get code
*
* @return string
*/
public function isCompleted()
{
return $this->completed;
}
}

B) Create TaskType form
-----------------------

For handling data comes from request we need to create our ``TaskType.php`` file with standard content
xabbuh marked this conversation as resolved.
Show resolved Hide resolved
(pleas note that we setup ``getName()`` method with ``'task'`` and ``'csrf_protection => false'`` - this is
xabbuh marked this conversation as resolved.
Show resolved Hide resolved
important for creating requests which we will do later):

.. code-block:: php

// src/AppBundle/Form/TaskType.php
namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class TaskType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('completed')
;
}

/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Task',
'csrf_protection' => false,
));
}

/**
* @return string
*/
public function getName()
{
return 'task';
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should be removed.

}

C) Create TaskController
------------------------

For expose our REST API methods (routes) lets add the following controller:

.. code-block:: php

// src/AppBundle/Controller/TaskController.php
namespace AppBundle\Controller;

use AppBundle\Entity\Task;
use AppBundle\Form\TaskType;
use FOS\RestBundle\Controller\Annotations\View;
use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class TaskController extends FOSRestController
{
/**
* List all tasks
xabbuh marked this conversation as resolved.
Show resolved Hide resolved
*
* @View
*/
public function getTasksAction()
{
return $this->getDoctrine()->getRepository('AppBundle:Task')->findAll();
xabbuh marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Show specific task
*
* @View
*/
public function getTaskAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$task = $em->getRepository('AppBundle:Task')->find($id);

if (!$task) {
throw $this->createNotFoundException();
}

return $task;
}

/**
* Create new task
*
* @View
*/
public function postTasksAction(Request $request)
{
$task = new Task();
$form = $this->createForm(TaskType::class, $task);

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($task);
$em->flush();

return $task;
}

throw new BadRequestHttpException();
xabbuh marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Update existing task
*
* @View
*/
public function putTasksAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$task = $em->getRepository('AppBundle:Task')->find($id);
if (!$task) {
throw $this->createNotFoundException();
}
$form = $this->createForm(TaskType::class, $task, [
'method' => 'PUT'
]);

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$em->persist($task);
$em->flush();

return $task;
}

throw new BadRequestHttpException();
}

/**
* Delete existing task
*
* @View
*/
public function deleteTasksAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$task = $em->getRepository('AppBundle:Task')->find($id);
if (!$task) {
throw $this->createNotFoundException();
}

$em->remove($task);
$em->flush();
}
}

D) Update routing.yml
---------------------

Lte's update routing configuration:

.. code-block:: yml

// app/config/routing.yml
tasks:
type: rest
resource: AppBundle\Controller\TaskController

E) Create database
------------------

We created our entity so we have to create database and schema:

.. code-block:: bash

$ bin/console doctrine:database:create
$ bin/console doctrine:schema:create

F) Test our API!
----------------

After setup our application it's time to test our REST API, so lets run the Symfony built in server:
xabbuh marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: bash
xabbuh marked this conversation as resolved.
Show resolved Hide resolved

$ bin/console server:run

and test our endpoints with ``curl`` or I recommend Postman google-chrome extension:

.. code-block:: bash

# get list of tasks
$ curl -X GET -H 'Content-Type: application/json' http://localhost:8000/tasks

# create new task
$ curl -X POST -H 'Content-Type: application/json' -d '{ "task": { "name": "name of the task", "completed": false } }' http://localhost:8000/tasks

# show task
$ curl -X GET -H 'Content-Type: application/json' http://localhost:8000/tasks/1

# update existing task
$ curl -X PUT -H 'Content-Type: application/json' -d '{ "task": { "name": "new name of the task", "completed": true } }' http://localhost:8000/tasks/1

# delete task
$ curl -X DELETE -H 'Content-Type: application/json' http://localhost:8000/tasks/1

That was it!