gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
It's you again! Welcome back friend! In this tutorial, we're diving back into Doctrine: this time to master database relations. And to have fun of course - databases are super fun.
Like usual, you should code along with me or risk 7 years of bad luck. Sorry. To do that, download the code from the course page and use the start
directory. I already have the code - so I'll startup our fancy, built-in web server:
./bin/console server:run
You may also need to run composer install
and a few other tasks. Check the README in the download for those details.
When you're ready, pull up the genus list page at http://localhost:8000/genus
. Nice!
Click to view a specific genus. See these notes down here? These are loaded via a ReactJS app that talks to our app like an API. But, the notes themselves are still hardcoded right in a controller. Bummer! Time to make them dynamic - time to create a second database table to store genus notes.
To do that, create a new GenusNote
class in the Entity
directory. Copy the ORM use
statement from Genus
that all entities need and paste it here:
... lines 1 - 2 | |
namespace AppBundle\Entity; | |
use Doctrine\ORM\Mapping as ORM; | |
... lines 6 - 10 | |
class GenusNote | |
{ | |
... lines 13 - 78 | |
} |
With that, open the "Code"->"Generate" menu - or Cmd
+ N
on a Mac - and select "ORM Class":
... lines 1 - 2 | |
namespace AppBundle\Entity; | |
use Doctrine\ORM\Mapping as ORM; | |
/** | |
* @ORM\Entity | |
* @ORM\Table(name="genus_note") | |
*/ | |
class GenusNote | |
{ | |
... lines 13 - 78 | |
} |
Bam! This is now an entity!
Next: add the properties we need. Let's see... we need a username
, an userAvatarFilename
, notes
and a createdAt
property:
... lines 1 - 10 | |
class GenusNote | |
{ | |
... lines 13 - 17 | |
private $id; | |
... lines 19 - 22 | |
private $username; | |
... lines 24 - 27 | |
private $userAvatarFilename; | |
... lines 29 - 32 | |
private $note; | |
... lines 34 - 37 | |
private $createdAt; | |
... lines 39 - 78 | |
} |
When we add a user table later - we'll replace username
with a relationship to that table. But for now, keep it simple.
Open the "Code"->"Generate" menu again and select "ORM Annotation". Make sure each field type
looks right. Hmm, we probably want to change $note
to be a text
type - that type can hold a lot more than the normal 255 characters:
... lines 1 - 10 | |
class GenusNote | |
{ | |
/** | |
* @ORM\Id | |
* @ORM\GeneratedValue(strategy="AUTO") | |
* @ORM\Column(type="integer") | |
*/ | |
private $id; | |
/** | |
* @ORM\Column(type="string") | |
*/ | |
private $username; | |
/** | |
* @ORM\Column(type="string") | |
*/ | |
private $userAvatarFilename; | |
/** | |
* @ORM\Column(type="text") | |
*/ | |
private $note; | |
/** | |
* @ORM\Column(type="datetime") | |
*/ | |
private $createdAt; | |
... lines 39 - 78 | |
} |
Finally, go back to our best friend - the "Code"->"Generate" menu - and generate the getter and setters for every field - except for id
. You don't usually want to set the id
, but generate a getter for it:
... lines 1 - 10 | |
class GenusNote | |
{ | |
... lines 13 - 39 | |
public function getId() | |
{ | |
return $this->id; | |
} | |
public function getUsername() | |
{ | |
return $this->username; | |
} | |
public function setUsername($username) | |
{ | |
$this->username = $username; | |
} | |
public function getUserAvatarFilename() | |
{ | |
return $this->userAvatarFilename; | |
} | |
public function setUserAvatarFilename($userAvatarFilename) | |
{ | |
$this->userAvatarFilename = $userAvatarFilename; | |
} | |
public function getNote() | |
{ | |
return $this->note; | |
} | |
public function setNote($note) | |
{ | |
$this->note = $note; | |
} | |
public function getCreatedAt() | |
{ | |
return $this->createdAt; | |
} | |
public function setCreatedAt($createdAt) | |
{ | |
$this->createdAt = $createdAt; | |
} | |
} |
Entity done! Well, almost done - we still need to somehow relate each GenusNote
to a Genus
. We'll handle that in a second.
But first, don't forget to generate a migration for the new table:
./bin/console doctrine:migrations:diff
Open up that file to make sure it looks right - it lives in app/DoctrineMigrations
. CREATE TABLE genus_note
- it looks great! Head back to the console and run the migration:
./bin/console doctrine:migrations:migrate
Man, that was easy. We'll want some good dummy notes too. Open up the fixtures.yml
file and add a new section for AppBundle\Entity\GenusNote
. Start just like before: genus.note_
and - let's create 100 notes - so use 1..100
:
... lines 1 - 8 | |
AppBundle\Entity\GenusNote: | |
genus.note_{1..100}: | |
... lines 11 - 15 |
Next, fill in each property using the Faker functions: username:
<username()> and then userAvatarFilename:
Ok, eventually users might upload their own avatars, but for now, we have two hardcoded options: leanna.jpeg
and ryan.jpeg
. Let's select one of these randomly with a sweet syntax: 50%?
leanna.jpeg : ryan.jpeg. That's Alice awesomeness:
... lines 1 - 7 | |
AppBundle\Entity\GenusNote: | |
genus.note_{1..100}: | |
username: <userName()> | |
userAvatarFilename: '50%? leanna.jpeg : ryan.jpeg' | |
... lines 13 - 15 |
The rest are easy: note: <paragraph()>
and createdAt:
<dateTimeBetween('-6 months', 'now')>:
... lines 1 - 8 | |
AppBundle\Entity\GenusNote: | |
genus.note_{1..100}: | |
username: <userName()> | |
userAvatarFilename: '50%? leanna.jpeg : ryan.jpeg' | |
note: <paragraph()> | |
createdAt: <dateTimeBetween('-6 months', 'now')> |
Ok, run the fixtures!
./bin/console doctrine:fixtures:load
Double-check them with a query:
./bin/console doctrine:query:sql 'SELECT * FROM genus_note'
So awesome! Ok team, we have two entities: let's add a relationship!
// 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
}
}