Buy Access to Course
04.

Finishing the Battle

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Head to the controller. We've got this form flow mastered! Step 1: create a new BattleModel object: $battleModel = new BattleModel():

// ... lines 1 - 11
class BattleController extends BaseController
{
/**
* @Route("/api/battles")
* @Method("POST")
*/
public function newAction(Request $request)
{
$battleModel = new BattleModel();
// ... lines 21 - 34
}
}

Step 2: create the form: $form = $this->createForm() with BattleType::class:

// ... lines 1 - 5
use AppBundle\Form\BattleType;
// ... lines 7 - 11
class BattleController extends BaseController
{
// ... lines 14 - 17
public function newAction(Request $request)
{
$battleModel = new BattleModel();
$form = $this->createForm(BattleType::class, $battleModel);
// ... lines 22 - 34
}
}

On my version of PhpStorm, I need to go back and re-type the e to trigger auto-completion so that the use statement is added above.

For the second argument to createForm: pass it $battleModel.

Step 3: Use $this->processForm():

// ... lines 1 - 11
class BattleController extends BaseController
{
// ... lines 14 - 17
public function newAction(Request $request)
{
$battleModel = new BattleModel();
$form = $this->createForm(BattleType::class, $battleModel);
$this->processForm($request, $form);
// ... lines 23 - 34
}
}

Remember, this is a method we added in BaseController:

187 lines | src/AppBundle/Controller/BaseController.php
// ... lines 1 - 19
abstract class BaseController extends Controller
{
// ... lines 22 - 142
protected function processForm(Request $request, FormInterface $form)
{
$data = json_decode($request->getContent(), true);
if ($data === null) {
$apiProblem = new ApiProblem(400, ApiProblem::TYPE_INVALID_REQUEST_BODY_FORMAT);
throw new ApiProblemException($apiProblem);
}
$clearMissing = $request->getMethod() != 'PATCH';
$form->submit($data, $clearMissing);
}
// ... lines 155 - 185
}

it decodes the Request body and submits it into the form, which is what we do on every endpoint that processes data.

Type-hint the Request argument for the controller and pass this to processForm().

If the form is not valid, we need to send back errors. Use another method from earlier: $this->throwApiProblemValidationException() and pass it the $form object:

// ... lines 1 - 11
class BattleController extends BaseController
{
// ... lines 14 - 17
public function newAction(Request $request)
{
$battleModel = new BattleModel();
$form = $this->createForm(BattleType::class, $battleModel);
$this->processForm($request, $form);
if (!$form->isValid()) {
$this->throwApiProblemValidationException($form);
}
// ... lines 27 - 34
}
}

This will grab the validation errors off and create that response.

At this point, we have a BattleModel object that's populated with the Programmer and Project objects sent in the request. To create the battle, we need to use the BattleManager. Do that with $this->getBattleManager() - that's just a shortcut to get the service - ->battle() and pass it $battleModel->getProgrammer() and $battleModel->getProject():

// ... lines 1 - 11
class BattleController extends BaseController
{
// ... lines 14 - 17
public function newAction(Request $request)
{
$battleModel = new BattleModel();
$form = $this->createForm(BattleType::class, $battleModel);
$this->processForm($request, $form);
if (!$form->isValid()) {
$this->throwApiProblemValidationException($form);
}
$battle = $this->getBattleManager()->battle(
$battleModel->getProgrammer(),
$battleModel->getProject()
);
// ... lines 32 - 34
}
}

Put a little $battle = in the beginning of all of this to get the new Battle object. Perfect!

Now that the battle has been heroically fought, let's send back the gory details. Use return $this->createApiResponse() and pass it $battle and the 201 status code:

// ... lines 1 - 11
class BattleController extends BaseController
{
// ... lines 14 - 17
public function newAction(Request $request)
{
$battleModel = new BattleModel();
$form = $this->createForm(BattleType::class, $battleModel);
$this->processForm($request, $form);
if (!$form->isValid()) {
$this->throwApiProblemValidationException($form);
}
$battle = $this->getBattleManager()->battle(
$battleModel->getProgrammer(),
$battleModel->getProject()
);
// todo - set Location header
return $this->createApiResponse($battle, 201);
}
}

We aren't setting a Location header yet, so let's at least add a todo for that.

We are done! Controller, model and form: these are the only pieces we need to create a robust endpoint. Try the test:

./vendor/bin/phpunit --filter testPOSTCreateBattle

We are in prime battling shape.

Now, let's complicate things and learn how to really take control of every field in our endpoint. And, learn more about relations.