If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
Let's finish this! Ultimately, we need to create the same $notes
structure, but
with the real data. Above the foreach
add a new $notes
variable. Inside, add
a new entry to that and start populating it with id => $note->getId()
:
... lines 1 - 12 | |
class GenusController extends Controller | |
{ | |
... lines 15 - 94 | |
public function getNotesAction(Genus $genus) | |
{ | |
$notes = []; | |
foreach ($genus->getNotes() as $note) { | |
$notes[] = [ | |
'id' => $note->getId(), | |
]; | |
} | |
... lines 104 - 114 | |
} | |
} |
Hey! Where's my autocompletion on that method!? Check out the getNotes()
method in
Genus
. Ah, there's no @return
- so PhpStorm has no idea what that returns. Sorry
PhpStorm - my bad. Add some PhpDoc with @return ArrayCollection|GenusNote[]
:
... lines 1 - 11 | |
class Genus | |
{ | |
... lines 14 - 105 | |
/** | |
* @return ArrayCollection|GenusNote[] | |
*/ | |
public function getNotes() | |
{ | |
return $this->notes; | |
} | |
} |
This will autocomplete any methods from ArrayCollection
and auto-complete
from GenusNote
if we loop over these results.
Now we get autocompletion for getId()
. Next, add username => $note->getUsername()
and I'll paste in the other fields: avatarUri
, note
and createdAt
. Ok, delete
that hardcoded stuff!
... lines 1 - 12 | |
class GenusController extends Controller | |
{ | |
... lines 15 - 94 | |
public function getNotesAction(Genus $genus) | |
{ | |
$notes = []; | |
foreach ($genus->getNotes() as $note) { | |
$notes[] = [ | |
'id' => $note->getId(), | |
'username' => $note->getUsername(), | |
'avatarUri' => '/images/'.$note->getUserAvatarFilename(), | |
'note' => $note->getNote(), | |
'date' => $note->getCreatedAt()->format('M d, Y') | |
]; | |
} | |
$data = [ | |
'notes' => $notes | |
]; | |
return new JsonResponse($data); | |
} | |
} |
Deep breath: moment of truth. Refresh! Ha! There are the 15 beautiful, random notes, courtesy of the AJAX request, Alice and Faker.
But wait - the order of the notes is weird: these should really be ordered from newest
to oldest. That's the downside of using the $genus->getNotes()
shortcut: you
can't customize the query - it just happens magically in the background.
Well ok, I'm lying a little bit: you can control the order. Open up Genus
and find the $notes
property. Add another annotation: @ORM\OrderBy
with
{"createdAt"="DESC"}
:
... lines 1 - 11 | |
class Genus | |
{ | |
... lines 14 - 45 | |
/** | |
* @ORM\OneToMany(targetEntity="GenusNote", mappedBy="genus") | |
* @ORM\OrderBy({"createdAt" = "DESC"}) | |
*/ | |
private $notes; | |
... lines 51 - 113 | |
} |
I know, the curly-braces and quotes look a little crazy here: just Google this if you can't remember the syntax. I do!
Ok, refresh! Hey! Newest ones on top, oldest ones on the bottom. So we do have some control. But if you need to go further - like only returning the GenusNotes that are less than 30 days old - you'll need to do a little bit more work.
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.1.*", // v3.1.4
"doctrine/orm": "^2.5", // v2.7.2
"doctrine/doctrine-bundle": "^1.6", // 1.6.4
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
"symfony/swiftmailer-bundle": "^2.3", // v2.3.11
"symfony/monolog-bundle": "^2.8", // 2.11.1
"symfony/polyfill-apcu": "^1.0", // v1.2.0
"sensio/distribution-bundle": "^5.0", // v5.0.22
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
"doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.0.7
"symfony/phpunit-bridge": "^3.0", // v3.1.3
"nelmio/alice": "^2.1", // 2.1.4
"doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
}
}