Query Logic Re-use & Shortcuts
…we can make the argument to addIsPublishedQueryBuilder()
also optional:
Inside, use the new method: return $this->getOrCreateQueryBuilder() passing it $qb,
and then our andWhere():
But the real beautiful thing is back up top. This whole method can now be one
big chained call: return $this…
EntityType Validation: Restrict Invalid programmerId
…and
clicking ProgrammerRepository. Add public function createQueryBuilderForUser()
with the User $user argument:
Inside, return $this->createQueryBuilder() and alias the class to programmer.
Then, just andWhere('programmer.user = :user') with ->setParameter('user', $user):
Done! The controller passes the User to the form, and the form…
Filtering / Searching
…set the old return value to a new $qb variable. Then, if ($filter) has some value,
add a where clause: andWhere('programmer.nickname LIKE :filter OR programmer.tagLine LIKE filter').
Then use setParameter('filter' , '%'.$filter.'%'). Finish things by returning $qb
at the bottom:
If you…
SELECT the SUM (or COUNT)
…Keep the alias consistent for an entity, it'll
save you heartache later.
Next, we need an andWhere() because we need to only find FortuneCookie
results for this Category. So, fc.category - because category is the
name of the property on FortuneCookie for the relationship…
DQL & The Query Builder
…the property... even though
the column in the table is asked_at. Now add ->orderBy() with
q.askedAt and DESC.
Oh, and notice that I'm using andWhere()... even though there are no WHERE
clauses before this! I'm doing this for 2 reasons. First..…
EntityType Checkboxes with ManyToMany
…list? Simple! Start by opening UserRepository: create
a new public function called createIsScientistQueryBuilder():
Very simple: return $this->createQueryBuilder('user'), andWhere('user.isScientist = :isScientist')
and finally, setParameter('isScientist', true):
This doesn't make the query: it just returns the query builder.
Over in GenusFormType, hook…
Querying on a Relationship
…id =
some number. The only tricky part is that the andWhere() is done on
the genus property - not the genus_id column: you always reference
property names with Doctrine.
Finish this with another andWhere('genus_note.createdAt > :recentDate') and
->setParameter('recentDate', new \DateTime(…
Twig Template Inheritance
…the
Homepage class. It's the same concept in Twig.
And these block names - like javascripts, stylesheets and body - aren't special
names... and they're not registered anywhere. Feel free to create new blocks however
and whenever you want. For example, suppose we want…
PHP Enums
…unpublished & draft - or sizes - small, medium
or large - or anything similar.
In the Model/ directory - though this could live anywhere... we're creating the
enum for our own organization - create a new class and call it StarshipStatusEnum.
As soon as I typed the word enum…
Twig Partials & for Loops
…These are called template
partials... since they hold code for just part of the page.
Copy this code, and in the main/ directory - though this could go anywhere - add
a new file called _shipStatusAside.html.twig. Paste inside.
Back in homepage.html.twig, delete that…
Non-Autowireable Arguments
…duplicating our autowired PHP attributes in multiple places. Super handy!
Since we're not currently using that parameter anywhere except our config, we
can get rid of this for now.
Next: Let's see how we can autowire non-autowireable services. It's
surprisingly easy.
Let’s Write some PHP!
…you see here is just an HTML page that I’ve loaded in my browser
http://localhost:8000/index.php
This is a template based on Twitter Bootstrap and it’s just a bunch of
hardcoded text and links that don’t go anywhere yet…
Processing the Submitted Form
…to unwanted parts floating around in space - let's finish the
process with a redirect. This is a classic best practice for POST forms.
Let's return $this->redirectToRoute().
We can redirect anywhere, but I'll send users back to the part list for
convenience…
Setting the Relation
…control the foreign key column: nullable: false means that every
StarshipPart must belong to a Starship.
So how do we say that this part belongs to this Starship?
The answer is beautifully simple. Anywhere before flush(), say
$part->setStarship($starship):
That's it. With Doctrine…
Injecting Config & Services and using Interfaces
…if we needed to use the mailer object somewhere else
in our app? Right now, we would need to create it anywhere we need it, since
it's buried inside FriendHarvester.
In fact, FriendHarvester doesn't really care how we're sending emails,
it only…
Accessing Data on a ManyToMany
…droid names
in two spots, so let's add a smart method for this in the Starship class. This
could go anywhere, but I'll stick it at the bottom with the other droid methods.
Create a public function getDroidNames(): string. To return a comma…
Filters: Automatically Modify Queries
…it is a two-step process.
First, in config/packages/doctrine.yaml, we need to tell Doctrine that the
filter exists. Anywhere directly under the orm key, add filters and then
fortuneCookie_discontinued. That string could be anything... and you'll see
how we use…
JOINs
…we want to JOIN across this fortuneCookies property over to the
FortuneCookie entity.
Let's do it! Back over in CategoryRepository... we can add the join anywhere in
the query. Unlike SQL, the QueryBuilder doesn't care what order you do things.
Add ->leftJoin() because…
SRP: Responsibilities
…code that
deals with hashing passwords and persisting user data? In a perfect world,
shouldn't I be able to create this "email resend" feature without going anywhere
near code that's unrelated to this functionality?
This is what SRP is trying to help us…
Validation
…when it hits the database because
some of the columns are null.
And, we expected this! We're missing validation. Adding validation to our API
is exactly like adding validation anywhere in Symfony. For example, find the
name property. We need name to be required…
x
513