0:00
Towards the end of the previous video, we had a working symphony controller class that could
0:04
handle our post data submission. And it could get us to a point where we had an associative array
0:09
representing the raw data that had been submitted. Now an array is useful. However, the data inside
0:14
is not very tidy. For example, the submitted date is a raw string, and we can actually get symphony
0:20
to convert this for us into an instance of date time or even date time immutable, if that's your
0:25
thing. Now once we've tidied up this submission, we need this data to stick around, which means
0:29
that we need to store it somewhere and that sounds like a good use case for doctrine now if we're
0:34
working with doctrine that means that we need an entity to represent our data structure now don't
0:39
be put off by the terminology an entity is simply a plain php class on which one of the properties
0:44
is an id field now there's more to an entity than that but that's the gist of it from the point
0:49
where we're at so let's make our album entity if you're comfortable working with entities then by
0:54
all means go ahead and create yours any which way that you see fit i'm going to use the maker bundle
0:59
specifically the make entity passing in album as the name of our entity. I'm simply going to follow
1:05
the prompts passing in the various property names that we need. We already know these from our b hat
1:11
test. We're going to need title, release date and track count. Now one thing that's interesting from
1:16
the b hat test is that we'll be passing in our data as for example release underscore date but
1:22
I'm going to use camel case property names for example release date all one word where the d in
1:28
date is capitalized as this is pretty much the standard when working with doctrine now one thing
1:33
to note there is that we didn't have to specify the id property we get that for us automatically
1:37
so we should now have an entity called album which we do you can see we've got our four properties
1:43
the three that we defined ourselves and the one that's automatically added for us likewise it's
1:47
gone ahead and generated the getters and setters for each of the three properties that we added
1:52
and just the getter for the id property the reason being that you never want to be manually setting
1:57
the id field of an entity now this is not the world's most beautiful entity but it is sufficient
2:02
for our needs it'd be nicer to move away from using setters and instead rely on the constructor
2:07
or name constructor methods to set properties of our entities however this does create complexity
2:12
when using symphony's form and it would lead to a more layered architecture than an application of
2:17
this complexity requires now if this topic interests you then please do leave a comment
2:21
as i'm happy to go into more depth on a more real world approach but it would be under a different
2:26
video. One nice thing is that each of the setters and getters has a defined return type
2:31
This is a PHP 7 feature that we can take advantage of inside a Symphony 4 application where the minimum PHP version required to run Symphony 4 is now 7 The last thing as mentioned is our release date and our track count both use CamelCase but our incoming BHAT test data is going to use SnakeCase
2:50
and this is not going to map one-to-one, so we will need to address this. So as we have our database up and running, as covered in a previous video
2:57
we can now either do a bin console, doctoring schema update for us
3:01
or we can make use of the migration as it recommends here. So let's do a bin console, make migration
3:06
and then let's run that migration with a bin console doctrine migrations migrate now no even
3:12
though it gives the full command here you can get away with the least amount that's still unique
3:17
and with that we should have our database set up and working you can of course use any database
3:23
client that you like including the cli i personally like data grip by jetbrains as it allows us to
3:28
work with both postgres and mysql databases so i'm going to set up a new connection here define
3:34
the name momentarily our host is just zero zero zero zero port is 3306 database db underscore dev
3:42
db user and db password looks like i need to download these missing driver files do a test
3:48
of the connection looks good so i'm just going to apply that i'll leave the database name as is
3:54
it's fine there we go see our table oh that completely threw me nope we're looking at the
4:02
wrong database there that's for a completely different project I wondered why it was called contact anyway it looks very similar just back to front just to keep me on my toes anyway there we
4:11
go we can see our database has been created and it's got the columns and properties that we set
4:16
on our entity now the best way that I know to turn arrays into entities is to use a symphony form
4:21
this way we gain access to all the structuring and validation and flexibility that symphony's
4:26
form component brings to the table now unfortunately this does add complexity over say just newing up
4:31
an entity and whacking in raw data via its setters. Fortunately with Symphony 4's maker bundle we do
4:37
reduce a bunch of the boilerplate typing so we can make a new form rather easily. With a bin console
4:43
make form and our form is just going to be the album type. Now this is very recently changed in
4:48
Symphony 4.0.6 I believe and by simply passing in the name of our entity it should be able to guess
4:54
all the different form fields that we want. So that's really nice. There's a couple of additional
5:00
things that I'm going to do on this form. I'm going to set the release date form field type
5:04
to be of type date time type. Now that's a bit of a mouthful, but essentially it's going to tell
5:10
Symfony that when working with the release date, we're actually working with strings that represent
5:15
date times Likewise our track count should be a number type Now before we get onto this issue of snake case and camel case there is another problem here so if we take a look at the body that we posting in our release date expects to be in
5:29
this string format like this but as it stands by using the date time type our form expects data to
5:36
come in looking like this so our release date would have to be broken down into two different
5:40
objects one's the date one's the time the date's got three different properties the time's got two
5:46
different properties and can you imagine going to your front end dev and saying yeah this is the
5:50
the date time format that we're working with they'd think you were crazy unfortunately symphony does
5:56
have us covered here so i'm just going to delete that before i forget and we'll go back and the
6:01
third argument to a builder's add method is the options which is just an array okay so we'll start
6:07
with the release date we'll set up some options on here and the first thing that we need to do is set
6:11
the widget. Now the widget just needs to be single text. You can find all the options and
6:16
their available values on the symphony docs. If you think about the widget being as like a HTML
6:22
form representation and you might have like three different drop downs for those date properties
6:27
that we saw and then two different ones for the time. Well when we're saying that the widget is
6:32
just single text it would just be represented by a single input field. In other words it's the
6:36
simple as possible way of accepting a date. Now the thing is we're submitting our date in a fairly
6:42
standard format for a JavaScript application. Unfortunately the date time type won't work well
6:47
with it unless we tell it the specific format that we're using. Now the format is a little bit
6:51
long-winded so what I would recommend is you just copy and paste this from the show notes and pretty
6:56
much any time that you need to accept dates from some sort of JavaScript front end you're going to
7:00
need this format. This works nicely with the ISO 8601 JavaScript date time representation. So this
7:06
fixes the date time issue now to fix the form field name issue we need to use the property path
7:11
option and this makes things a little bit odd so what i'm going to do is going to add a new option
7:15
in here called property path which is fine and then we're going to set the property path to be
7:20
release date now that's the release date in camel case format and what we now need to do
7:25
is change the release date field name to be release underscore date in other words the snake case
7:30
format that we're going to expect our front end our javascript to be posting the data in as it's
7:36
a little bit weird it's back to front in a way that's how it feels to me we also need to do this
7:40
for our track count as well so there's property path and this one will be track count in camel
7:45
case and that means our field name will be track count in snake case we'll just see if php storm
7:51
will play nice and reformat this code to make it look pretty well i'll take it there's one final
7:57
change that we need to make here and that to turn off CSRF protection So CSRF protection we going to set that to be false The reason being is that we expecting data from other sites in this case CSRF just doesn apply here So given what we described in our BHAT post test
8:13
the incoming data submission should now be happily meeting the expectation of our album type
8:18
We're going to use the album controller to pass the incoming post through our form
8:22
The form will transform the array of data into a populated album instance
8:26
Now, as the album has all the doctrine annotations, we can then save or persist our newly populated album entity off to our database. So let's add
8:35
this logic into our album controller and get rid of that exit statement and we'll create a new form
8:41
which will say this create form which will be our album type and we'll pass in a new album instance
8:47
as the form's initial data. So on that form instance we're going to call its internal submit method
8:53
passing in that associative array of data. After the internal form submission process has taken
8:59
place we can check if the form is valid and if it's not valid then we want to return a new json
9:05
response where we'll say the status is error and the response code well we'll want a 400 error
9:12
ideally so set this to bad request now this won't be perfect to begin with because we're not going
9:19
to be sending back any information as to what went wrong now we need a way to save or persist
9:24
this newly updated album instance off to our database. Now to do that we're going to need
9:29
access to the entity manager and we could either inject it into our post method or because we're
9:35
going to need the entity manager in all the other methods such as get and collection get and put and
9:39
patch and delete we might as well inject it generally so that it's available in all of the
9:44
different methods. So we'll create our constructor and we can inject the entity manager interface
9:49
because the only implementation of that interface is going to be doctoring so we should be good
9:53
there and then we can use that so say this entity manager persist and we need to get the form get
10:01
data in other words our album and then we need to immediately call flush to actually save that
10:06
information off to the database so that should actually give us a passing b hat test so what
10:12
i'm going to do is i'm going to jump across to the b hat project and i'm going to tag this one
10:16
with the tag of t you can tag it with anything you like but t is just the easiest thing and that
10:21
This means we'll just be able to run that one individual test. So do a vendor BIMBY hat with the tags of T
10:27
So anything with the tag of T should get run. And that looks quite good
10:31
And what's really nice is actually we will get more than just one album in our database here
10:35
We should have four. So let's check that is the case. The three background steps ran and they were implicitly posting in
10:42
And then our actual explicit post test ran and passed. So there we go