WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:01.096 --> 00:00:05.036 align:middle
We've just created a new branch
based off of Symfony's master branch.

00:00:05.456 --> 00:00:10.706 align:middle
And now, we're ready to create the
amazing new TargetPathHelper class.

00:00:11.246 --> 00:00:13.366 align:middle
But... where should it live?

00:00:14.456 --> 00:00:15.886 align:middle
It's related to Security...

00:00:16.106 --> 00:00:20.756 align:middle
which means it could live in the
Security component or SecurityBundle.

00:00:22.106 --> 00:00:25.756 align:middle
As a general rule, most code
should live in a component

00:00:25.926 --> 00:00:28.906 align:middle
so that it's reusable even
outside of the framework.

00:00:29.716 --> 00:00:34.566 align:middle
But, sometimes, you'll write code that's
really integrated with the framework.

00:00:35.286 --> 00:00:37.006 align:middle
That code will live in the bundle.

00:00:37.966 --> 00:00:39.296 align:middle
My best advice...

00:00:39.476 --> 00:00:44.886 align:middle
don't over-think it: it usually becomes pretty
obvious if you put something in the wrong spot.

00:00:45.986 --> 00:00:50.056 align:middle
Press Shift+Shift and search for
a file that's closely related

00:00:50.056 --> 00:00:52.976 align:middle
to our new feature: TargetPathTrait.

00:00:54.836 --> 00:00:57.516 align:middle
Ok, this lives in the Security component.

00:00:57.516 --> 00:01:00.376 align:middle
I'll double click on the
directory to move there.

00:01:01.456 --> 00:01:05.556 align:middle
At first, it seems like TargetPathHelper
should live right here.

00:01:06.196 --> 00:01:09.866 align:middle
And that's where I would put it at first.

00:01:10.536 --> 00:01:15.876 align:middle
I say "at first" because, if you
started coding, you'd notice a problem.

00:01:16.776 --> 00:01:17.746 align:middle
What problem?

00:01:18.416 --> 00:01:24.116 align:middle
This new class will ultimately use the
FirewallMap class internally to do its work.

00:01:25.416 --> 00:01:30.536 align:middle
There are two FirwallMap classes:
one lives in the Security component,

00:01:30.876 --> 00:01:33.046 align:middle
and the other lives in SecurityBundle.

00:01:33.116 --> 00:01:40.056 align:middle
After digging a little bit, you'd find out that
we will need to use the one from SecurityBundle.

00:01:40.726 --> 00:01:45.656 align:middle
And here's why that's important:
a class in a component can depend

00:01:45.656 --> 00:01:47.596 align:middle
on classes from other components.

00:01:48.516 --> 00:01:52.706 align:middle
But, it can never depend
on a class from a bundle.

00:01:53.756 --> 00:01:57.646 align:middle
Because our new TargetPathHelper
needs a class from SecurityBundle,

00:01:57.956 --> 00:02:01.706 align:middle
it can't live in the component:
it must live in the bundle.

00:02:01.706 --> 00:02:07.236 align:middle
If you get this wrong, no big deal: someone
will help you out on your pull request.

00:02:08.056 --> 00:02:10.606 align:middle
Go find SecurityBundle and look inside Security.

00:02:11.466 --> 00:02:17.816 align:middle
Hey! Here are the FirewallMap and
FirewallConfig classes we'll be using!

00:02:18.576 --> 00:02:19.696 align:middle
That's a good sign!

00:02:20.716 --> 00:02:24.236 align:middle
Create the new PHP class: TargetPathHelper.

00:02:27.046 --> 00:02:34.736 align:middle
Add our first public function, how about
just savePath() with a string $uri argument:

00:02:34.736 --> 00:02:43.376 align:middle
Symfony 4.0 and above requires PHP 7.1, so you
should use scalar type-hints and return types.

00:02:43.886 --> 00:02:47.376 align:middle
But, Symfony does not use the void return type.

00:02:48.776 --> 00:02:53.196 align:middle
Because this is a public function, we
should add some PHPDoc to describe it.

00:02:54.396 --> 00:02:59.256 align:middle
Add a clear, but short description
above this: Actually,

00:02:59.596 --> 00:03:02.546 align:middle
Symfony does not have a lot of PHPDoc...

00:03:02.816 --> 00:03:05.036 align:middle
which might seem weird at first.

00:03:05.876 --> 00:03:10.836 align:middle
The reason is that we don't want to maintain
too much documentation inside the code -

00:03:11.206 --> 00:03:13.786 align:middle
we use a separate repository for documentation.

00:03:14.946 --> 00:03:17.466 align:middle
Oh, and, thanks to the string type-hint,

00:03:17.646 --> 00:03:23.376 align:middle
the @param documentation is totally
redundant and should be removed...

00:03:24.166 --> 00:03:30.316 align:middle
unless there's some valuable extra
info that you want to say about it.

00:03:30.316 --> 00:03:32.266 align:middle
I'll keep it and add some extra notes...

00:03:32.606 --> 00:03:39.756 align:middle
even though it doesn't add a lot of
extra context: Also every PHP file

00:03:39.756 --> 00:03:42.376 align:middle
in Symfony should have a
copyright header on top.

00:03:43.306 --> 00:03:50.626 align:middle
Grab that from another file and paste it here:
Don't worry too much about these details:

00:03:50.876 --> 00:03:53.006 align:middle
it's easy to add them later if you forget.

00:03:54.106 --> 00:03:59.136 align:middle
To make life nicer, use TargetPathTrait
on top of the class:

00:04:00.316 --> 00:04:06.636 align:middle
Then all we need to do is say
$this-&gt;saveTargetPath(): But...

00:04:06.926 --> 00:04:11.726 align:middle
hmm... this needs 3 arguments:
the session, provider key -

00:04:11.956 --> 00:04:14.586 align:middle
which is the firewall name - and the URI.

00:04:15.586 --> 00:04:20.536 align:middle
We know that we can get the firewall
name by using the FirewallMap service.

00:04:22.206 --> 00:04:29.986 align:middle
Let's add some constructor arguments:
SessionInterface $session and FirewallMap -

00:04:30.366 --> 00:04:37.986 align:middle
the one from SecurityBundle - $firewallMap: I'll
press Alt+Enter and select initialize fields

00:04:38.116 --> 00:04:44.806 align:middle
to create those properties and set them: Make
sure to remove the PHPDoc above each property:

00:04:45.686 --> 00:04:49.756 align:middle
this is redundant thanks to
the constructor type-hints.

00:04:52.236 --> 00:04:55.376 align:middle
To calculate the provider key,
create a new private function:

00:04:55.476 --> 00:04:58.256 align:middle
getProviderKey() that will return a string.

00:04:59.596 --> 00:05:07.556 align:middle
For now, just put a TODO: Back up in
setTargetPath(), pass $this-&gt;session,

00:05:07.556 --> 00:05:14.016 align:middle
$this-&gt;getProviderKey() and the $uri: Awesome!

00:05:15.026 --> 00:05:20.166 align:middle
Look back at getProviderKey():
I didn't add any PHPDoc

00:05:20.166 --> 00:05:24.246 align:middle
to this function, but that's
not because I'm lazy.

00:05:24.646 --> 00:05:26.786 align:middle
Or... not entirely because I'm lazy.

00:05:27.596 --> 00:05:29.176 align:middle
Really, it's for two reasons.

00:05:29.226 --> 00:05:35.986 align:middle
First, this is a private function, and those
are typically not documented inside Symfony.

00:05:36.496 --> 00:05:41.886 align:middle
And second, we already have the return
type - no reason to duplicate it!

00:05:41.886 --> 00:05:44.116 align:middle
Lets finish this function.

00:05:45.156 --> 00:05:48.236 align:middle
To get the firewall name, we
need to use the FirewallMap,

00:05:48.686 --> 00:05:52.286 align:middle
call getFirewallConfig()
and pass it the request.

00:05:52.386 --> 00:06:00.806 align:middle
Ok: $firewallConfig =
$this-&gt;firewallMap-&gt;getFirewallConfig().

00:06:02.436 --> 00:06:03.946 align:middle
But, hmm...

00:06:04.326 --> 00:06:06.696 align:middle
we don't have the Request object!

00:06:07.926 --> 00:06:14.626 align:middle
No problem: add a third constructor
arg: RequestStack $requestStack.

00:06:14.626 --> 00:06:19.176 align:middle
I'll hit Alt+Enter again to
create that property and set it.

00:06:20.876 --> 00:06:27.836 align:middle
Clean off the PHPDoc, then head back
down: Normally, when you use RequestStack,

00:06:28.146 --> 00:06:32.096 align:middle
you call its getCurrentRequest()
method to get the request.

00:06:32.916 --> 00:06:40.786 align:middle
But, in this case, I'm going to use another
method: $this-&gt;requestStack-&gt;getMasterRequest():

00:06:41.906 --> 00:06:45.006 align:middle
I'm not 100% sure that this is correct.

00:06:45.916 --> 00:06:50.156 align:middle
The whole topic of requests and
sub-requests is pretty complex.

00:06:50.606 --> 00:06:57.886 align:middle
But, basically, Symfony's security firewall
only operates on the outer, "master" request.

00:06:58.976 --> 00:07:02.446 align:middle
So, to find the active firewall,
that's what we should use.

00:07:02.446 --> 00:07:06.576 align:middle
If I'm wrong, hopefully someone
will tell me on the pull request.

00:07:07.876 --> 00:07:10.706 align:middle
Next, if you look at the
getFirewallConfig() method,

00:07:11.116 --> 00:07:14.066 align:middle
it's possible that this will return null.

00:07:14.066 --> 00:07:20.626 align:middle
Code for that: if null === $firewallConfig:

00:07:21.806 --> 00:07:27.416 align:middle
This is another Symfony coding
convention: we use Yoda conditionals!

00:07:27.996 --> 00:07:31.166 align:middle
Mysterious, Symfony's coding conventions are.

00:07:31.216 --> 00:07:31.886 align:middle
Herh herh herh.

00:07:32.716 --> 00:07:38.996 align:middle
But hey! If the force isn't strong with you
today, don't worry: Symfony has a magic way

00:07:38.996 --> 00:07:42.466 align:middle
of fixing coding convention
problems that I'll show you later.

00:07:42.466 --> 00:07:48.106 align:middle
If there is no firewall config for
some reason, throw a new LogicException

00:07:48.506 --> 00:07:53.256 align:middle
with as clear a message as
possible: Why a LogicException?

00:07:53.976 --> 00:07:57.566 align:middle
Well, it seems to make sense
- something went wrong...

00:07:57.566 --> 00:07:58.316 align:middle
logically.

00:07:58.656 --> 00:08:01.706 align:middle
And usually, the exact exception
class won't matter.

00:08:02.646 --> 00:08:06.686 align:middle
If it does matter, someone will
tell you when reviewing your PR.

00:08:06.766 --> 00:08:14.386 align:middle
Finally, at the bottom, return
$firewallConfig-&gt;getName(): That should be it!

00:08:14.386 --> 00:08:22.256 align:middle
While we're here, let's add one more
function: getPath() that will return a string.

00:08:23.536 --> 00:08:31.136 align:middle
Inside, return $this-&gt;getTargetPath() with
$this-&gt;session and $this-&gt;getProviderKey():

00:08:32.336 --> 00:08:35.216 align:middle
This time, I will add some PHPDoc.

00:08:35.926 --> 00:08:40.656 align:middle
I don't need @return - that's
redundant - but I will add a description

00:08:40.716 --> 00:08:43.476 align:middle
about what this method does: And...

00:08:43.656 --> 00:08:44.246 align:middle
we're done!

00:08:45.376 --> 00:08:49.826 align:middle
Yea, we still need to write a test
&amp; add some config to register this

00:08:49.826 --> 00:08:52.356 align:middle
as a service: we'll do that next.

00:08:52.986 --> 00:08:55.966 align:middle
But, this class should work!

00:08:57.076 --> 00:08:57.656 align:middle
However...

00:08:58.146 --> 00:09:09.006 align:middle
I am going to make one, ahem, final change:
add final: Making this class final means

00:09:09.006 --> 00:09:11.626 align:middle
that nobody is allowed to subclass it.

00:09:12.316 --> 00:09:14.016 align:middle
Why are we doing this?

00:09:14.606 --> 00:09:20.936 align:middle
Because, in the future, if the class is
final, it will be easier to make changes to it

00:09:21.136 --> 00:09:23.316 align:middle
without breaking backwards compatibility.

00:09:24.226 --> 00:09:27.926 align:middle
Basically, if you allow a
class to be sub-classed,

00:09:28.306 --> 00:09:31.466 align:middle
you have to be a bit more careful
when making certain changes.

00:09:32.386 --> 00:09:36.506 align:middle
Making classes final is a good
"default" for new Symfony classes.

00:09:37.906 --> 00:09:42.096 align:middle
Of course, if there is a legitimate
use-case for some to sub-class this,

00:09:42.476 --> 00:09:44.706 align:middle
then you don't need to make it final.

00:09:45.386 --> 00:09:52.326 align:middle
But, while we can easily remove final
later, we can't add final in the future,

00:09:52.956 --> 00:09:59.026 align:middle
at least not without jumping through a few extra
hoops to avoid breaking backwards compatibility.

00:10:00.176 --> 00:10:03.506 align:middle
Ok, let's add some service config &amp; a test!

