If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeGoogle for "HATEOAS PHP" to find a fun library that a friend of mine made. This library has a bundle that integrates it into Symfony: so click to view the BazingaHateoasBundle and go straight to its docs. Before we talk about what it does: get it installed.
Copy the composer require statement and then flip over to your terminal and paste that:
composer require willdurand/hateoas-bundle
This is a bundle, so grab the new bundle statement, open AppKernel
and pop that at the bottom:
... lines 1 - 5 | |
class AppKernel extends Kernel | |
{ | |
public function registerBundles() | |
{ | |
$bundles = array( | |
... lines 11 - 21 | |
new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(), | |
); | |
... lines 24 - 33 | |
} | |
... lines 35 - 52 | |
} |
Perfect. Currently, we have our own super sweet annotation system for adding links. In Battle
, we use @Link
to create a programmer
link:
... lines 1 - 9 | |
/** | |
... lines 11 - 13 | |
* @Link( | |
* "programmer", | |
* route="api_programmers_show", | |
* params={"nickname": "object.getProgrammerNickname()"} | |
* ) | |
*/ | |
class Battle | |
... lines 21 - 138 |
Guess what! I completely stole that idea from this library. But now, to make our app a little simpler and to get some new features, let's replace our @Link
code with this library.
Go back to the library itself, and scroll down to the first coding example. This uses an annotation system that looks pretty similar to ours. Copy the use
statement on top, open Battle
and paste that:
... lines 1 - 8 | |
use Hateoas\Configuration\Annotation as Hateoas; | |
... lines 10 - 141 |
Next, change the annotation to @Hateoas\Relation
:
... lines 1 - 10 | |
/** | |
... lines 12 - 14 | |
* @Hateoas\Relation( | |
... lines 16 - 20 | |
* ) | |
*/ | |
class Battle | |
... lines 24 - 141 |
Keep programmer
: that will still be the link's rel
. But add href=@Hateoas\Route
and pass that the name of the route: api_programmers_show
:
... lines 1 - 10 | |
/** | |
... lines 12 - 14 | |
* @Hateoas\Relation( | |
* "programmer", | |
* href=@Hateoas\Route( | |
* "api_programmers_show", | |
... line 19 | |
* ) | |
* ) | |
*/ | |
class Battle | |
... lines 24 - 141 |
Update params
to parameters
, and inside, set nickname
equal, and wrap the expression in expr()
:
... lines 1 - 10 | |
/** | |
... lines 12 - 14 | |
* @Hateoas\Relation( | |
* "programmer", | |
* href=@Hateoas\Route( | |
* "api_programmers_show", | |
* parameters={"nickname"= "expr(object.getProgrammerNickname())"} | |
* ) | |
* ) | |
*/ | |
class Battle | |
... lines 24 - 141 |
That translates our annotation format to the one used by the bundle. And the result is almost the same. Open BattleControllerTest
and copy the first method name:
... lines 1 - 6 | |
class BattleControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTCreateBattle() | |
... lines 17 - 74 | |
} |
we have a test for a link near the bottom of this:
... lines 1 - 6 | |
class BattleControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTCreateBattle() | |
{ | |
... lines 18 - 40 | |
$this->asserter()->assertResponsePropertyEquals( | |
$response, | |
'_links.programmer', | |
$this->adjustUri('/api/programmers/Fred') | |
); | |
... lines 46 - 48 | |
} | |
... lines 50 - 74 | |
} |
Change over to the terminal and, as long as Composer is done, run:
vendor/bin/phpunit --filter testPOSTCreateBattle
Check it out! It fails - but barely. This library still puts links under an _links
key, but instead of listing the URLs directly, it wraps each inside an object with an href
key. That's causes the failure.
Ok, fair enough. Let's fix that by updating the test to look for _links.programmer.href
:
... lines 1 - 6 | |
class BattleControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTCreateBattle() | |
{ | |
... lines 18 - 40 | |
$this->asserter()->assertResponsePropertyEquals( | |
$response, | |
'_links.programmer.href', | |
$this->adjustUri('/api/programmers/Fred') | |
); | |
... lines 46 - 48 | |
} | |
... lines 50 - 74 | |
} |
Run the test again:
vendor/bin/phpunit --filter testPOSTCreateBattle
And now we're green.
But guess what? It's no accident that this library used this exact format: with an _links
key and an href
below that. This is a semi-official standard format called HAL JSON.
Yo Chris!
The bundle should work just fine with Symfony 3 as well :). Their composer.json supports Symfony 2 and 3: https://github.com/willdura...
If you're having any issues, let us know!
Cheers!
in composer I have:
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.0.*",
"doctrine/orm": "^2.5",
"doctrine/doctrine-bundle": "^1.6",
"doctrine/doctrine-cache-bundle": "^1.2",
"symfony/swiftmailer-bundle": "^2.3",
"symfony/monolog-bundle": "^2.8",
"sensio/distribution-bundle": "^5.0",
"sensio/framework-extra-bundle": "^3.0.2",
"incenteev/composer-parameter-handler": "~2.0",
"jms/serializer-bundle": "^1.1.0",
"white-october/pagerfanta-bundle": "^1.0",
"lexik/jwt-authentication-bundle": "^1.4",
"willdurand/hateoas": "^2.11"
},
In AppKernel.php:
$bundles = array(
new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle()
)
Even I put in composer.json:
"autoload": {
"psr-4": {
"": "src/",
"App\\Behat\\": "features/",
"Bazinga\\Bundle\\HateoasBundle\\": ""
},
"classmap": [ "app/AppKernel.php", "app/AppCache.php" ]
},
The net result when I run testPostCreateBattle test is:
PHP Fatal error: Uncaught Error: Class 'Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle' not found in restSymfony/app/AppKernel.php:22
Hey Diaconescu!
Hmmm. I see willdurand/hateoas in your composer.json, but you actually need willdurand/hateoas-bundle
. Maybe that was just a little typo? Try running composer require willdurand/hateoas-bundle
. I think (hope) it will fix the issue!
Cheers!
Unfortunately Is not a typo. In the link you provided as response for months ago(https://github.com/willdura... is the same string in require section for hateoas. And doesn't work.
Hey Diaconescu!
Hmm. But in the tutorial, we say to install the bundle: https://knpuniversity.com/screencast/symfony-rest5/hateoas-php-library#installing-bazingahateoasbundle
composer require willdurand/hateoas-bundle
Is there somewhere else that we recommend installing the library, instead of the bundle? I think there could be a bug somewhere, but I don't see it yet :).
Cheers!
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.0.*", // v3.0.3
"doctrine/orm": "^2.5", // v2.5.4
"doctrine/doctrine-bundle": "^1.6", // 1.6.2
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
"symfony/swiftmailer-bundle": "^2.3", // v2.3.11
"symfony/monolog-bundle": "^2.8", // v2.10.0
"sensio/distribution-bundle": "^5.0", // v5.0.4
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.14
"incenteev/composer-parameter-handler": "~2.0", // v2.1.2
"jms/serializer-bundle": "^1.1.0", // 1.1.0
"white-october/pagerfanta-bundle": "^1.0", // v1.0.5
"lexik/jwt-authentication-bundle": "^1.4", // v1.4.3
"willdurand/hateoas-bundle": "^1.1" // 1.1.1
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.0.6
"symfony/phpunit-bridge": "^3.0", // v3.0.3
"behat/behat": "~3.1@dev", // dev-master
"behat/mink-extension": "~2.2.0", // v2.2
"behat/mink-goutte-driver": "~1.2.0", // v1.2.1
"behat/mink-selenium2-driver": "~1.3.0", // v1.3.1
"phpunit/phpunit": "~4.6.0", // 4.6.10
"doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
}
}
Is there a similar bundle for Symfony 3?