Buy

The Battle representation includes the username of the programmer that fought. If you want more information about Fred, you can make a request to /api/programmers/Fred:

70 lines tests/AppBundle/Controller/Api/BattleControllerTest.php
... lines 1 - 6
class BattleControllerTest extends ApiTestCase
{
... lines 9 - 15
public function testPOSTCreateBattle()
{
... lines 18 - 37
$this->asserter()
->assertResponsePropertyEquals($response, 'programmer', 'Fred');
... lines 40 - 42
}
... lines 44 - 68
}

That's something we'll document.

But! Wouldn't it be even more convenient if we added a link to that URL inside of the Battle representation? Then, instead of needing to go look up and hardcode the URL, the client could simply read and follow the link.

Whenever a link like this would be helpful, add it! First, look for it in the test: $this->asserter()->assertResponsePropertyEquals(). For consistency, we decided to put links under an _links key. So, look for _links.programmer. This should equal $this->adjustUri('/api/programmers/Fred):

76 lines tests/AppBundle/Controller/Api/BattleControllerTest.php
... lines 1 - 37
$this->asserter()
->assertResponsePropertyEquals($response, 'programmer', 'Fred');
$this->asserter()->assertResponsePropertyEquals(
$response,
'_links.programmer',
$this->adjustUri('/api/programmers/Fred')
);
... lines 46 - 76

All this method does is help account for the extra app_test.php that's in the URL when testing:

373 lines src/AppBundle/Test/ApiTestCase.php
... lines 1 - 21
class ApiTestCase extends KernelTestCase
{
... lines 24 - 358
/**
* Call this when you want to compare URLs in a test
*
* (since the returned URL's will have /app_test.php in front)
*
* @param string $uri
* @return string
*/
protected function adjustUri($uri)
{
return '/app_test.php'.$uri;
}
}

Perfect! Now, let's go add that link. First, open up the Programmer entity. We added the self link earlier via a cool annotation system we created:

198 lines src/AppBundle/Entity/Programmer.php
... lines 1 - 9
/**
... lines 11 - 15
* @Link(
* "self",
* route = "api_programmers_show",
* params = { "nickname": "object.getNickname()" }
* )
*/
class Programmer
... lines 23 - 198

In Battle, add something similar: @Link - let that auto-complete for the use statement. Set the name - or rel - of the link to programmer. This is the significance of the link: it could be anything, as long as you consistently use programmer when linking to a programmer:

138 lines src/AppBundle/Entity/Battle.php
... lines 1 - 9
/**
... lines 11 - 13
* @Link(
* "programmer",
... lines 16 - 17
* )
*/
class Battle
... lines 21 - 138

For the route, use api_programmers_show: the route name to a single programmer:

138 lines src/AppBundle/Entity/Battle.php
... lines 1 - 9
/**
... lines 11 - 13
* @Link(
* "programmer",
* route="api_programmers_show",
... line 17
* )
*/
class Battle
... lines 21 - 138

Finally, add params: the wildcard parameters that need to be passed to the route. This route has a nickname wildcard. Set it to an expression: object.getProgrammerNickname():

138 lines src/AppBundle/Entity/Battle.php
... lines 1 - 9
/**
... lines 11 - 13
* @Link(
* "programmer",
* route="api_programmers_show",
* params={"nickname": "object.getProgrammerNickname()"}
* )
*/
class Battle
... lines 21 - 138

That's the method we created down below earlier:

138 lines src/AppBundle/Entity/Battle.php
... lines 1 - 19
class Battle
{
... lines 22 - 119
/**
* @Serializer\VirtualProperty()
* @Serializer\SerializedName("programmer")
*/
public function getProgrammerNickname()
{
return $this->programmer->getNickname();
}
... lines 128 - 136
}

And that's all we need. Copy the method name again - testPostCreateBattle() - and run the test:

./vendor/bin/phpunit --filter testPostCreateBattle

And it works.

Now, let me show you an awesome library that makes adding links even easier. In fact, I stole the @Link annotation idea from it.

Leave a comment!