WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:00.286 --> 00:00:03.386 align:middle
Welcome. Hi.

00:00:03.386 --> 00:00:07.686 align:middle
Hello. The stage is huge, it's intimidating,

00:00:09.716 --> 00:00:18.646 align:middle
but we're pretty happy that
so many of you joined us.

00:00:19.516 --> 00:00:21.336 align:middle
And we're talking about Symfony forms.

00:00:22.386 --> 00:00:24.686 align:middle
So who have you used Symfony forms before?

00:00:25.966 --> 00:00:26.786 align:middle
Oh, that's an easy one.

00:00:26.786 --> 00:00:33.376 align:middle
Right? And we're talking about Symfony
forms using rich domain models.

00:00:33.616 --> 00:00:35.486 align:middle
Who's familiar with the term rich domain model.

00:00:37.426 --> 00:00:46.516 align:middle
So quite a few and uh, but we are
starting with introducing ourselves.

00:00:46.516 --> 00:00:49.336 align:middle
So let's do this.

00:00:49.396 --> 00:00:58.096 align:middle
That is Christian, Christian is working
for SensioLabs, in Germany and uh,

00:00:58.266 --> 00:01:01.736 align:middle
besides being a software developer at
SensioLabs he's working as a core member

00:01:01.736 --> 00:01:04.946 align:middle
of Symfony software and Symfony docs.

00:01:06.396 --> 00:01:11.086 align:middle
And this guy next to me is Christopher,
he's working at SensioLabs in Germany too.

00:01:11.546 --> 00:01:15.896 align:middle
And he's also one of the organizers
of Symfony user group in Berlin.

00:01:16.086 --> 00:01:19.966 align:middle
So if you ever come to Berlin
and you're lucky to,

00:01:19.966 --> 00:01:23.436 align:middle
to attend the user group,
you may meet him there too.

00:01:23.896 --> 00:01:31.396 align:middle
And Christopher will now guide you through
a simple example application that we created

00:01:31.486 --> 00:01:35.256 align:middle
to show you the concepts of our talk.

00:01:35.256 --> 00:01:38.636 align:middle
So in order to make it easier
to understand everything.

00:01:39.446 --> 00:01:43.266 align:middle
Yeah. Well, so we're doing it
hands on with a simple use case

00:01:43.266 --> 00:01:46.426 align:middle
and our use case is a simple product CRUD.

00:01:46.776 --> 00:01:49.696 align:middle
CRUD is an abbreviation for
create, read, update, delete.

00:01:49.696 --> 00:01:55.686 align:middle
I think you're familiar with that principal,
a principal and a, it looks like that.

00:01:56.406 --> 00:01:58.196 align:middle
It's a simple interface.

00:01:58.886 --> 00:02:00.586 align:middle
Looks a lot like bootstrap I guess.

00:02:00.966 --> 00:02:04.476 align:middle
And there are two forms in it.

00:02:05.016 --> 00:02:08.786 align:middle
So, one about the category
and one about the product.

00:02:09.616 --> 00:02:15.246 align:middle
And the domain is a product with
a name, a category, and a price.

00:02:16.196 --> 00:02:16.596 align:middle
Pretty simple.

00:02:17.476 --> 00:02:24.476 align:middle
On the category itself has a name and an
optional parent category pretty simple as well.

00:02:24.896 --> 00:02:35.156 align:middle
And the price object has an
amount tax rate and a currency.

00:02:35.276 --> 00:02:39.886 align:middle
So, uh, that's the workflow of
the forms and we're talking just

00:02:39.886 --> 00:02:45.126 align:middle
about the product form with a create and edit.

00:02:46.346 --> 00:02:48.526 align:middle
So you're quite familiar with that.

00:02:48.526 --> 00:02:57.286 align:middle
I guess it's a very simple action that
handles, uh, both steps the create and edit.

00:02:58.806 --> 00:03:03.776 align:middle
So let's see, at the very basic
solution, that's pretty much a,

00:03:03.776 --> 00:03:07.086 align:middle
like the best practice document
in the documentation.

00:03:08.026 --> 00:03:17.096 align:middle
So we're having a product controller with a form
action and that's just creating the form type,

00:03:17.096 --> 00:03:23.216 align:middle
handling the request, binding request to
the form type and then the very typical,

00:03:23.376 --> 00:03:31.076 align:middle
if it's submitted and it's valid structure
with a redirect at the end or the rendering

00:03:31.456 --> 00:03:35.556 align:middle
of the form optional with
data and errors or plain.

00:03:36.156 --> 00:03:40.836 align:middle
The form type itself, is
very straightforward as well.

00:03:41.686 --> 00:03:44.866 align:middle
So we're having a product
type with a name category,

00:03:44.866 --> 00:03:47.566 align:middle
price amount, price tax and price currency.

00:03:47.566 --> 00:03:51.636 align:middle
So we're not having a price
object on this level,

00:03:52.196 --> 00:03:55.946 align:middle
but three price attributes and the product type.

00:03:56.426 --> 00:04:00.046 align:middle
And we're binding the product
product class to the type.

00:04:00.516 --> 00:04:03.436 align:middle
Next up, the Product class.

00:04:03.536 --> 00:04:08.846 align:middle
So the model, which is the
focus of our talk today, right?

00:04:09.056 --> 00:04:09.426 align:middle
The model.

00:04:10.376 --> 00:04:17.596 align:middle
And we're having a simple, a simple
product entity with a private properties

00:04:17.816 --> 00:04:26.626 align:middle
with assertion annotations on it and
simple getters and setters, right?

00:04:27.676 --> 00:04:30.066 align:middle
So pretty straightforward.

00:04:34.566 --> 00:04:38.766 align:middle
So, um, what's happening now
when we are getting our forms.

00:04:38.876 --> 00:04:44.636 align:middle
So, um, this is the form as you will see it in
your browser and you will enter data and so on,

00:04:44.806 --> 00:04:47.366 align:middle
and your browser will submit an HTTP request.

00:04:47.366 --> 00:04:55.016 align:middle
You can see on the headers and then
you have the body of the POST request

00:04:55.016 --> 00:04:57.116 align:middle
with all the data coming from the form.

00:04:58.356 --> 00:05:05.576 align:middle
And inside your your front controller,
the incoming request will be transformed

00:05:05.576 --> 00:05:10.446 align:middle
into a request object which is part
of the http foundation component,

00:05:10.446 --> 00:05:14.866 align:middle
which is an object oriented
layout on top of the super global.

00:05:14.866 --> 00:05:20.376 align:middle
It's basically what PHP offers
you to handle HTTP requests

00:05:20.376 --> 00:05:24.076 align:middle
and this is what it looks like
if we dumped the structure.

00:05:24.076 --> 00:05:29.056 align:middle
So you basically have an object
around a structured array.

00:05:29.106 --> 00:05:37.996 align:middle
And then inside your controller on this
side, you have the request object on top,

00:05:38.116 --> 00:05:40.906 align:middle
which is then passed down into
the handle request method,

00:05:40.956 --> 00:05:45.526 align:middle
which means that the request is
handled by the form component

00:05:45.526 --> 00:05:50.586 align:middle
and we can later check if
form was submitted or not.

00:05:51.986 --> 00:05:52.936 align:middle
Yes, right here.

00:05:54.036 --> 00:06:04.266 align:middle
And here the form is taking into account that
we are binding our form to the product class.

00:06:05.496 --> 00:06:12.826 align:middle
This was the final object, all the data that was
coming into our controller was bound by the form

00:06:12.826 --> 00:06:15.066 align:middle
and is now part of the form object.

00:06:17.176 --> 00:06:22.536 align:middle
So let's take a look at three
columns of our three types of code

00:06:22.536 --> 00:06:24.406 align:middle
that are involved to solve our problem.

00:06:24.406 --> 00:06:29.826 align:middle
First, there was third party code that we just
want to use that we don't want to maintain

00:06:29.826 --> 00:06:33.606 align:middle
that we don't want to write ourselves,
which means the front controller,

00:06:33.606 --> 00:06:37.106 align:middle
which is just bootstrap code from a application.

00:06:37.446 --> 00:06:43.136 align:middle
We have the HttpFoundation component as
the object oriented layout on top of HTTP.

00:06:43.136 --> 00:06:46.036 align:middle
We have the form component of course.

00:06:46.706 --> 00:06:51.256 align:middle
And we have the validator component
which we have seen in the product model

00:06:51.256 --> 00:06:54.546 align:middle
than we have added assertions to our model to,

00:06:54.546 --> 00:07:00.346 align:middle
to ensure that domain roots
are taken into account.

00:07:00.686 --> 00:07:05.256 align:middle
Then we have our domain layout, which
means the core part of our business.

00:07:05.546 --> 00:07:08.256 align:middle
Everything that's individual
for our application,

00:07:09.266 --> 00:07:12.536 align:middle
which is basically the product
class the category class

00:07:12.666 --> 00:07:17.556 align:middle
and the price class or the price price object.

00:07:18.166 --> 00:07:25.446 align:middle
And then we need to write some glue code
to somehow wrap all these things together.

00:07:25.606 --> 00:07:32.596 align:middle
And this is the controller, which means we
are handling the request that we are dealing

00:07:32.646 --> 00:07:34.546 align:middle
with a request and returning a response.

00:07:35.206 --> 00:07:41.686 align:middle
We need to create a form type which
describes how we map our request to our model

00:07:42.646 --> 00:07:50.356 align:middle
and if we take a look at this from a graphical
point of view, we have the data flowing in from,

00:07:50.616 --> 00:07:57.636 align:middle
from the left and going through all the layouts
in our model, our model is bound to the form

00:07:57.636 --> 00:08:04.106 align:middle
which is then handling the request
and putting data back into the model.

00:08:04.906 --> 00:08:12.416 align:middle
So usually we want to focus on these yellow
blocks, which is the core part of our business.

00:08:12.476 --> 00:08:17.596 align:middle
And we usually want to reduce the green part.

00:08:17.656 --> 00:08:25.166 align:middle
So the part that is just there for coupling our
domain to the framework to the least minimum.

00:08:26.056 --> 00:08:29.076 align:middle
Okay. So that's the basic setup.

00:08:30.486 --> 00:08:32.226 align:middle
Probably nothing new for you.

00:08:32.926 --> 00:08:38.466 align:middle
And the next step is that we look at our
model, um, and we need to differentiate

00:08:38.466 --> 00:08:41.556 align:middle
about anemic domain model and rich domain model.

00:08:42.296 --> 00:08:50.506 align:middle
What we saw, the product type and the product is
a dynamic domain model which is focused on data.

00:08:51.546 --> 00:08:55.146 align:middle
So there's a structured way
of having data in an object.

00:08:57.026 --> 00:09:03.836 align:middle
It's very easy to implement and to maintain
even you can generate it using helpers,

00:09:03.836 --> 00:09:11.146 align:middle
like MakerBundle or a or the
PhpStorm has some utilities as well.

00:09:11.796 --> 00:09:19.646 align:middle
And it contains little or no logic at all,
so maybe no constructor, no validation logic

00:09:19.646 --> 00:09:24.956 align:middle
and setters, and it's not
guaranteed that the data that is

00:09:25.036 --> 00:09:29.376 align:middle
in their object is valid or is consistent.

00:09:31.406 --> 00:09:32.756 align:middle
So that might be a problem.

00:09:33.616 --> 00:09:41.016 align:middle
Rich domain model combines data and
logic and it is valid by design.

00:09:41.536 --> 00:09:44.546 align:middle
So we have mandatory constructor
arguments, for example.

00:09:45.626 --> 00:09:50.626 align:middle
So we need to give a category name and
category can't exist without a name.

00:09:51.466 --> 00:09:53.296 align:middle
It's quite easy to test.

00:09:54.176 --> 00:09:57.616 align:middle
Same is true for the anemic domain model,

00:09:57.946 --> 00:10:02.916 align:middle
but some might argue it's not really
sensible to test the anemic domain model.

00:10:03.446 --> 00:10:11.916 align:middle
And we can now create state
transitions by name and test them

00:10:12.286 --> 00:10:14.716 align:middle
and um, do assertions on transitions.

00:10:15.526 --> 00:10:21.176 align:middle
And that's the last point, defined
state transitions and we can, um,

00:10:21.696 --> 00:10:28.186 align:middle
the concept is to be more explicit,
explicit on the names of state transitions

00:10:28.346 --> 00:10:32.996 align:middle
and not just have set name,
but uh, maybe rename process.

00:10:37.596 --> 00:10:41.796 align:middle
Important small disclaimer,
we don't want to lecture you

00:10:41.796 --> 00:10:44.776 align:middle
about using rich domain models
is the best way to do it.

00:10:45.776 --> 00:10:47.896 align:middle
It's sensible to choose between them.

00:10:48.046 --> 00:10:50.866 align:middle
Right? And that's, that's up to you.

00:10:51.426 --> 00:11:00.136 align:middle
And uh, this guy, Martin Fowler wrote in 2003
that anemic domain models are anti-pattern

00:11:01.066 --> 00:11:07.356 align:middle
and then stack overflow was a bit
curious if it's an anti-pattern or not.

00:11:08.246 --> 00:11:15.496 align:middle
And then there was discussions how they
differ and how to avoid anemic domain models,

00:11:15.896 --> 00:11:20.096 align:middle
how to find the right balance
between using both maybe.

00:11:20.766 --> 00:11:23.336 align:middle
Um, someone came up with this idea.

00:11:23.546 --> 00:11:24.846 align:middle
It's not an anti-pattern anymore.

00:11:26.146 --> 00:11:28.446 align:middle
Someone says it's SOLID design.

00:11:30.056 --> 00:11:35.506 align:middle
Some said it's not SOLID, rich domain is
SOLID and stack overflow was very confused.

00:11:38.816 --> 00:11:44.486 align:middle
So that's the basic bottom line
at stack overflow article about it

00:11:44.486 --> 00:11:46.336 align:middle
and how not to agree about software design.

00:11:47.996 --> 00:11:54.266 align:middle
And we just want to point out their
differences and reasons to use one of them.

00:11:55.626 --> 00:12:01.136 align:middle
Anemic models are good for prototyping,
very, very easy to use, easily generated

00:12:01.586 --> 00:12:08.476 align:middle
and rich models are more about clean code and
object oriented, um, testability and yeah,

00:12:08.626 --> 00:12:16.496 align:middle
we can design our domain in it including
using name transitions and process.

00:12:17.336 --> 00:12:20.246 align:middle
Um, but it's your choice, right?

00:12:20.786 --> 00:12:28.586 align:middle
But the next point is we want to show you
how to use rich domain models with Symfony.

00:12:29.586 --> 00:12:35.066 align:middle
So if we take a look at our former model,
we didn't have any defined state methods

00:12:35.066 --> 00:12:40.656 align:middle
since we had just setter and getter methods so
you would have to call them however you like

00:12:40.656 --> 00:12:44.296 align:middle
and then you would have to run validation after.

00:12:44.296 --> 00:12:46.356 align:middle
That's not how we want put that.

00:12:46.806 --> 00:12:52.906 align:middle
So the first step is to, to, um,
require every attribute to be passed

00:12:53.146 --> 00:12:55.356 align:middle
when we are constructing the product.

00:12:55.496 --> 00:12:58.286 align:middle
So we have to put the name,
the category and the price.

00:12:59.056 --> 00:13:04.026 align:middle
For category and price we can be
sure that both are already valid

00:13:04.386 --> 00:13:05.966 align:middle
because these routes apply there too.

00:13:06.336 --> 00:13:10.576 align:middle
But for the name we need to, to
perform some, some validation.

00:13:10.576 --> 00:13:14.676 align:middle
We need to, to make sure
that that the constraints

00:13:14.876 --> 00:13:19.656 align:middle
that we defined are still applying here.

00:13:19.656 --> 00:13:26.326 align:middle
And you can also see that we have removed the
validation assertions, so this is something

00:13:26.326 --> 00:13:30.086 align:middle
that is now happening inside our, our model.

00:13:30.756 --> 00:13:37.136 align:middle
The same, happens here when we are renaming
our product and you can also see now

00:13:37.426 --> 00:13:41.516 align:middle
that we don't have a set named method
anymore, but we have a rename method now

00:13:41.706 --> 00:13:46.516 align:middle
so this is more like, like describing
what we are doing with our model.

00:13:48.256 --> 00:13:53.986 align:middle
And here's our validateName method, which was
just basically checking the length of our name.

00:13:55.996 --> 00:14:03.336 align:middle
The price is a bit special because
the price itself is not identified

00:14:03.366 --> 00:14:04.936 align:middle
by an id or something like that.

00:14:05.416 --> 00:14:09.166 align:middle
Um, price, just, well having a value.

00:14:09.476 --> 00:14:15.656 align:middle
And this is what makes it so special
because one price object can now be shared

00:14:15.736 --> 00:14:17.496 align:middle
between different products.

00:14:17.786 --> 00:14:21.866 align:middle
But if we are doing that
now we want to compare them.

00:14:22.096 --> 00:14:24.006 align:middle
So the value must not change.

00:14:24.756 --> 00:14:29.926 align:middle
And this means that our price
object has to be immutable.

00:14:30.876 --> 00:14:35.416 align:middle
We will see that later, what that
means for our forms after that.

00:14:35.416 --> 00:14:40.316 align:middle
So we're doing all the validation again.

00:14:41.406 --> 00:14:44.116 align:middle
And the same applies for the category.

00:14:45.436 --> 00:14:50.386 align:middle
So if we are now using this model
without making any other changes,

00:14:50.736 --> 00:14:56.226 align:middle
we would run into many different
exceptions and well that's not really funny.

00:14:56.436 --> 00:15:02.966 align:middle
Um, so we need to do something about that
to make our forms usable with our new model.

00:15:04.236 --> 00:15:12.246 align:middle
So the first solution that we came up with
is using data transfer objects or DTOs.

00:15:12.746 --> 00:15:17.336 align:middle
That's quite easy and looks like this.

00:15:17.596 --> 00:15:25.106 align:middle
That's the DTO having public properties
and the validation assertions on it.

00:15:26.336 --> 00:15:37.316 align:middle
And then we are having some kind of mapping
methods where we map the rich domain model

00:15:37.566 --> 00:15:43.766 align:middle
to an DTO and back again to an entity.

00:15:44.246 --> 00:15:48.556 align:middle
So right here we can check if
the DTO, if there are changes

00:15:48.616 --> 00:15:54.716 align:middle
and we can explicitly call those rename,
moveToCategory or even the Costs method

00:15:55.256 --> 00:15:59.056 align:middle
and apply those changes only when we need them.

00:16:00.236 --> 00:16:02.196 align:middle
So that's pretty easy to do.

00:16:02.976 --> 00:16:08.246 align:middle
And the code looks a bit
like the model before, right?

00:16:09.746 --> 00:16:16.516 align:middle
Um, the product type is actually
the same besides the small change

00:16:17.446 --> 00:16:19.616 align:middle
down there, changing the data class.

00:16:20.136 --> 00:16:31.646 align:middle
The controller is a bit different because
we have to map the DTO from entity

00:16:32.076 --> 00:16:39.446 align:middle
and to get the DTO from the form and map
to the entity again before persisting it.

00:16:39.786 --> 00:16:44.206 align:middle
So quite simple steps, but we
now can use rich domain models.

00:16:44.476 --> 00:16:46.846 align:middle
Right? Okay.

00:16:47.556 --> 00:16:50.116 align:middle
From the user's point of
view, that's not so much

00:16:50.116 --> 00:16:54.166 align:middle
that is just changing the interface
still looks the same as before the data

00:16:54.166 --> 00:16:59.706 align:middle
that is sent is still the same, it's still
transformed into the request object, as before.

00:16:59.706 --> 00:17:06.156 align:middle
And, the interesting changes are happening here
now because as Christopher already explained,

00:17:06.776 --> 00:17:10.936 align:middle
the entity is first transformed into the DTO

00:17:11.066 --> 00:17:14.486 align:middle
because we need to, to unbind
the form to this DTO.

00:17:15.116 --> 00:17:23.916 align:middle
We're handling the request here now and
here we see the binding to the DTO again,

00:17:25.566 --> 00:17:34.076 align:middle
we have the reside here this is the DTO and we
need to um, transform this back into the entity.

00:17:34.076 --> 00:17:38.866 align:middle
So we are catching the data
from form and parking it here.

00:17:39.676 --> 00:17:46.886 align:middle
Um, the entity so we can now
persist this entity again.

00:17:47.866 --> 00:17:51.016 align:middle
This three column model that
we have already seen before.

00:17:51.016 --> 00:17:57.616 align:middle
And what changes here now is the right column,
because we now have additional glue code.

00:17:57.726 --> 00:18:05.486 align:middle
We have written DTOs and this is more code
than before, um, which you can see here too.

00:18:05.836 --> 00:18:12.616 align:middle
So before, we only had our model here and now
we also have a green rectangle on the left

00:18:12.666 --> 00:18:19.066 align:middle
and on the right and well basically
we want to reduce this part.

00:18:19.066 --> 00:18:25.516 align:middle
Now we have have added some, so um, maybe that's
not the best solution we can come up with.

00:18:26.776 --> 00:18:31.446 align:middle
But the solution enables us to use rich
domain models by decoupling the model

00:18:31.446 --> 00:18:36.226 align:middle
from the form type and it's very easy
to implement and maintain as well.

00:18:36.706 --> 00:18:38.416 align:middle
So the DTO was quite simple.

00:18:39.596 --> 00:18:42.046 align:middle
Um, but it's additional glue code.

00:18:42.046 --> 00:18:48.876 align:middle
Right? And I don't know if you saw that, but
we have redundant validation rules, right?

00:18:49.206 --> 00:18:55.196 align:middle
We have validation in our rich domain model
and we need to have validation in our DTO.

00:18:56.186 --> 00:19:00.396 align:middle
So this one has an impact
on the maintainability.

00:19:00.876 --> 00:19:06.146 align:middle
Next solution we came up with is harder.

00:19:08.626 --> 00:19:13.726 align:middle
Okay. Who of you has implemented
a data mapper for forms before?

00:19:14.466 --> 00:19:15.816 align:middle
Okay, one, two, three.

00:19:16.296 --> 00:19:17.856 align:middle
Okay. 10 or 20 or so.

00:19:18.336 --> 00:19:24.196 align:middle
So I'm not so many and yes, I think
it's really the hardest solution,

00:19:24.286 --> 00:19:27.416 align:middle
but we want to explain it
nonetheless to show you.

00:19:27.416 --> 00:19:32.716 align:middle
Um, and I think it's, if you've never
used it before, it might be quite fast,

00:19:32.716 --> 00:19:37.716 align:middle
but it's not the point to explain data mappers,
we just want to show that it's possible

00:19:37.716 --> 00:19:42.246 align:middle
to use data mappers as a solution to
decouple and use rich domain models.

00:19:42.746 --> 00:19:51.016 align:middle
Yes. So our controller now looks again
the same as it was in our first solution

00:19:51.016 --> 00:19:54.096 align:middle
when we were using the anemic
domain, which basically means

00:19:54.146 --> 00:19:58.716 align:middle
that we are now again binding
the product entity to the form.

00:19:58.716 --> 00:20:07.166 align:middle
And the form is the part
where things changed now.

00:20:08.026 --> 00:20:15.716 align:middle
First we introduced a new price object which
is just extracting the price related properties

00:20:15.716 --> 00:20:18.656 align:middle
from the product and put it into a new model.

00:20:20.026 --> 00:20:25.966 align:middle
And now we have a data mapper,
so a custom data mapper.

00:20:25.966 --> 00:20:29.196 align:middle
The form component ships with a
default one, but we cannot use that.

00:20:29.756 --> 00:20:36.066 align:middle
Um, so we add a new one here and we just
say, okay, The data mapper that we want

00:20:36.066 --> 00:20:38.916 align:middle
to use is implemented inside, this product type.

00:20:39.066 --> 00:20:43.216 align:middle
You could also move it into another
class that doesn't really matter here

00:20:43.216 --> 00:20:46.656 align:middle
and a data mapper has two methods, methods.

00:20:46.976 --> 00:20:50.776 align:middle
The first one is this one
is called mapDataToForms

00:20:50.776 --> 00:20:55.026 align:middle
and it's populating the form
with the initial initial data.

00:20:55.766 --> 00:21:02.786 align:middle
So we, basically here take the
subtypes and set the data based

00:21:02.786 --> 00:21:05.066 align:middle
on the model that was passed here.

00:21:05.066 --> 00:21:08.676 align:middle
So the data variable is our product entity.

00:21:09.226 --> 00:21:16.776 align:middle
And after the form has been submitted, we must
remap the data from the form into our entity

00:21:17.336 --> 00:21:22.776 align:middle
and this was the part where things
are a little bit more complicated now

00:21:22.776 --> 00:21:24.936 align:middle
because we don't have any
setter methods anymore.

00:21:25.406 --> 00:21:29.096 align:middle
Um, so we are first getting
the data from the form,

00:21:29.866 --> 00:21:33.226 align:middle
comparing them to the data inside our entity,

00:21:33.226 --> 00:21:38.436 align:middle
and then we call our state
transitions, state transitioning methods.

00:21:38.586 --> 00:21:46.226 align:middle
So for example, rename here or here, we are
moving our product into a different category

00:21:46.226 --> 00:21:51.046 align:middle
or the price changes and we are
calling this method in this case.

00:21:53.206 --> 00:21:59.686 align:middle
When we are creating a new product,
we need to make sure that the form is

00:21:59.936 --> 00:22:05.706 align:middle
as populate a new product entity is
populated with the submitted data

00:22:06.776 --> 00:22:09.886 align:middle
and we are doing this here
with the empty data option.

00:22:09.886 --> 00:22:16.196 align:middle
Passing it a closure where we get the form
and we can extract all the data from the form

00:22:16.376 --> 00:22:19.316 align:middle
and pass it to the constructor
of our product entity.

00:22:19.746 --> 00:22:25.166 align:middle
We need to make sure here that we catch
all the exceptions that could occur

00:22:25.346 --> 00:22:27.996 align:middle
so that the user does not
see an internal server error,

00:22:27.996 --> 00:22:32.626 align:middle
but we can present them some
kind of a nicer error message.

00:22:36.456 --> 00:22:40.806 align:middle
The data flow, it's still the
same, or basically the same.

00:22:40.806 --> 00:22:46.566 align:middle
Here's a little bit, a little difference that
you can see because we now have the price

00:22:46.566 --> 00:22:50.836 align:middle
as an additional nested element,
but that's just a small detail here.

00:22:51.156 --> 00:22:59.296 align:middle
Yeah, we moved the price values to a lower
type, right, so we have a price type right now.

00:22:59.866 --> 00:23:01.366 align:middle
Submitted data is still the same.

00:23:01.366 --> 00:23:08.086 align:middle
The user does not change what they want
to enter there and you can see here

00:23:08.986 --> 00:23:12.396 align:middle
that the controller now is the
same as in the first example.

00:23:13.656 --> 00:23:18.956 align:middle
The request was handled again and here
is the difference, we are now not not,

00:23:19.626 --> 00:23:25.166 align:middle
the FormType still is bound to the product
entity, but the important part now is

00:23:25.316 --> 00:23:28.646 align:middle
that we have created our own
data method that is used here.

00:23:29.676 --> 00:23:34.896 align:middle
And the resulting Product, that's the
important part is still maintained.

00:23:35.306 --> 00:23:39.956 align:middle
We are basically changing what's
happening when our form is handled,

00:23:39.956 --> 00:23:42.026 align:middle
but we're not changing our model.

00:23:45.706 --> 00:23:50.856 align:middle
Here our three column model
that we are familiar with now.

00:23:50.856 --> 00:23:51.626 align:middle
Changes a bit.

00:23:52.916 --> 00:24:00.686 align:middle
Now, we don't have DTOs, but we have data
mappers and the validator component is gone too

00:24:01.176 --> 00:24:06.456 align:middle
because in the process, step one,
we introduce in the second step

00:24:06.616 --> 00:24:12.286 align:middle
when we introduced our rich domain model,
we are implementing our domain assertions

00:24:12.526 --> 00:24:16.796 align:middle
by by doing the validation inside
our methods and throwing exceptions

00:24:17.286 --> 00:24:22.986 align:middle
and now that we don't have DTOs anymore, we also
do not need the validator component anymore.

00:24:24.786 --> 00:24:32.526 align:middle
But the glue code part still makes
a big part of our application.

00:24:32.526 --> 00:24:38.696 align:middle
We have now data mappers that we need to
maintain, that we need to change where we need

00:24:38.696 --> 00:24:45.716 align:middle
to think about how can we test them,
which is yeah, massively different story

00:24:45.716 --> 00:24:51.626 align:middle
because testing data mappers really is not
fun and um, but you probably want to do

00:24:51.626 --> 00:24:53.886 align:middle
that because this is an important
part of your application.

00:24:55.756 --> 00:25:01.406 align:middle
So the bottom line with data mappers
enabled, enables us to use rich domain models

00:25:02.336 --> 00:25:06.466 align:middle
and that requires advanced
knowledge about the form component

00:25:06.886 --> 00:25:09.446 align:middle
and the extension points of the form component.

00:25:10.916 --> 00:25:13.686 align:middle
And this is additional glue code as well.

00:25:14.176 --> 00:25:22.376 align:middle
Like it's not a with redundant validation rules
we got rid of that but it's quite hard to test

00:25:22.436 --> 00:25:27.026 align:middle
and it's quite hard to understand
if you're getting in a new project

00:25:27.026 --> 00:25:32.176 align:middle
and there's data mappers all over the place.

00:25:32.286 --> 00:25:39.416 align:middle
So, DTO's, redundant data mappers are hard.

00:25:39.416 --> 00:25:41.106 align:middle
Maybe we can, we can ask questions.

00:25:41.106 --> 00:25:45.846 align:middle
So who have you after just
having heard this, um,

00:25:45.846 --> 00:25:48.836 align:middle
would like to use rich domain
models with Symfony forms?

00:25:49.666 --> 00:25:54.926 align:middle
Oh, okay. That's not so many.

00:25:54.926 --> 00:25:55.616 align:middle
Would you prefer.

00:25:55.616 --> 00:26:00.396 align:middle
So I think it was five or four people.

00:26:00.516 --> 00:26:02.096 align:middle
Would you use DTOs?

00:26:02.976 --> 00:26:05.706 align:middle
Or would you use data mappers?

00:26:06.366 --> 00:26:09.266 align:middle
Oh, okay. Half and half I think.

00:26:10.206 --> 00:26:19.566 align:middle
Okay. But uh, yeah, I mean it's clear that
this is maybe not the best solution yet.

00:26:19.566 --> 00:26:25.876 align:middle
We have another one, RichModelFormsBundle.

00:26:26.246 --> 00:26:29.526 align:middle
Yeah, we could, we could work on the name.

00:26:29.526 --> 00:26:33.286 align:middle
Okay. But it's already out there.

00:26:33.286 --> 00:26:37.516 align:middle
So it's RichModelFormsBundle.

00:26:37.596 --> 00:26:39.966 align:middle
So, um, you can easily install it.

00:26:41.586 --> 00:26:42.586 align:middle
It's still experimental.

00:26:42.806 --> 00:26:49.596 align:middle
So we're working on the idea and uh, today is
once again a kick off for a discussion, maybe.

00:26:50.496 --> 00:26:54.946 align:middle
The installation is quite easy
with a tool called Composer.

00:26:55.586 --> 00:26:59.506 align:middle
Um, and now we're talking about the features.

00:27:00.786 --> 00:27:03.666 align:middle
So yeah, basically the idea
behind this bundle is,

00:27:03.726 --> 00:27:08.336 align:middle
and that's why we have shown
you the third solution that the,

00:27:08.336 --> 00:27:14.186 align:middle
the data mapper approach maybe could be
generalized to something where you do not need

00:27:14.296 --> 00:27:20.276 align:middle
to write the code yourself, but you would
just configure this generic data mapper

00:27:20.276 --> 00:27:23.746 align:middle
so that it does what you
want based on your use cases.

00:27:23.876 --> 00:27:28.766 align:middle
And um, yeah, now it's your turn.

00:27:29.536 --> 00:27:31.316 align:middle
Thanks. Again.

00:27:31.956 --> 00:27:37.736 align:middle
First feature different write and read property
path, there is an option already property paths,

00:27:37.736 --> 00:27:44.466 align:middle
whether you can configure how the
property accessor, um, talks to your model,

00:27:45.266 --> 00:27:52.336 align:middle
but the new thing is that we can use, read
and write property path, um, different.

00:27:52.616 --> 00:27:58.726 align:middle
Because the problem with the initial, um,
within default data mapper is that the getters

00:27:58.726 --> 00:28:02.046 align:middle
and setters must really be
named getName and setName.

00:28:02.046 --> 00:28:08.896 align:middle
In this case, we'll look at this example and um,
yeah, we didn't want to have a setName method

00:28:08.936 --> 00:28:10.786 align:middle
because in our domain it's called rename.

00:28:11.336 --> 00:28:16.756 align:middle
So, um, we thought, okay, why don't we
split the property path in, read and write.

00:28:17.826 --> 00:28:21.766 align:middle
And yeah, that's the name,
read_property_path and write_property_path.

00:28:22.386 --> 00:28:28.496 align:middle
So in our case we are saying, okay, when
you're reading the value, you just call getName

00:28:28.496 --> 00:28:32.396 align:middle
and please call rename when
we want to change the value.

00:28:32.876 --> 00:28:39.146 align:middle
You could also pass a closure there if you
need to to maybe call different methods based

00:28:39.146 --> 00:28:43.406 align:middle
on the value of a checkbox, for example,
because you maybe have, enable and disable

00:28:43.406 --> 00:28:46.786 align:middle
and not something like set
enabled with true and false.

00:28:47.756 --> 00:28:53.056 align:middle
A quick side note, the bundle implements a
couple of form options, additional form options

00:28:53.346 --> 00:28:56.126 align:middle
that you can use on your form type.

00:28:57.586 --> 00:28:58.776 align:middle
So, exception handling.

00:28:59.066 --> 00:29:06.416 align:middle
So our domain model throws exceptions on
invalid input or on maybe in constructor,

00:29:08.036 --> 00:29:11.776 align:middle
like this was the price object, right?

00:29:12.526 --> 00:29:18.726 align:middle
Yes. And what you can now use is
the expected_exception option.

00:29:18.726 --> 00:29:24.916 align:middle
We are not really satisfied with this name
because it reminds us more what we're used

00:29:24.916 --> 00:29:31.586 align:middle
to when we are, um, using php unit, but in
fact we don't want the exception to be thrown.

00:29:31.586 --> 00:29:34.656 align:middle
We just want the bundle to intercept here.

00:29:34.716 --> 00:29:41.436 align:middle
So yeah, if you have ideas for a better name,
we would really welcome any suggestion here.

00:29:42.106 --> 00:29:46.156 align:middle
Um, but I think the idea should,
should be pretty clear so you can,

00:29:46.156 --> 00:29:52.566 align:middle
can define which exceptions can occur
here and which are valid to be thrown

00:29:52.566 --> 00:29:58.636 align:middle
because they might be thrown by domain
validations here and we want to show something

00:29:58.736 --> 00:30:04.216 align:middle
to the user, some kind of of nice error
message to show them what they did wrong.

00:30:04.446 --> 00:30:09.656 align:middle
Yeah, I guess the, the error handling
of the domain is quite important part.

00:30:09.656 --> 00:30:17.036 align:middle
We need to tackle because the exception
message is not very good for the interface,

00:30:17.186 --> 00:30:19.596 align:middle
so we need to, uh, to decouple that.

00:30:20.056 --> 00:30:26.586 align:middle
And maybe there are some other validation
concepts out there, not using exceptions,

00:30:26.626 --> 00:30:29.566 align:middle
but using a message bags and something.

00:30:30.166 --> 00:30:34.546 align:middle
One thing we didn't mention yet is
that all type errors that may occur

00:30:34.616 --> 00:30:37.336 align:middle
because you passed the wrong data type

00:30:37.446 --> 00:30:41.196 align:middle
to the method will automatically
caught being caught too.

00:30:41.196 --> 00:30:47.386 align:middle
So if you, um, have a model, you will
often have realized that you will have

00:30:47.506 --> 00:30:52.426 align:middle
to allow null values being there,
and this will be intercepted as well.

00:30:53.516 --> 00:30:56.066 align:middle
Next one, mandatory constructor arguments.

00:30:56.686 --> 00:31:00.416 align:middle
The form component, uh, creates objects, right?

00:31:00.876 --> 00:31:06.866 align:middle
And, um, there's an empty data option and
you can hand over already created objects.

00:31:07.556 --> 00:31:14.706 align:middle
But in this case where we have an immutable
value object or a value object, it's quite hard.

00:31:15.586 --> 00:31:21.716 align:middle
This also applies for product entity,
and yes, we could work around that

00:31:21.846 --> 00:31:26.676 align:middle
by writing this closure ourselves,
but that's um,

00:31:26.926 --> 00:31:29.386 align:middle
10 lines of code ourselves for every form type.

00:31:29.916 --> 00:31:36.296 align:middle
So, um, let's define a new option which is
called factory and factory can be the name

00:31:36.296 --> 00:31:41.746 align:middle
of a class, which means, um, all the,
um, values of this type would be passed

00:31:41.746 --> 00:31:43.366 align:middle
to the constructor of this class.

00:31:43.366 --> 00:31:50.616 align:middle
You could also, um, pass a closure on any
PHP callable, um, so maybe if setting method

00:31:50.616 --> 00:31:55.956 align:middle
on another class or so, and this
would then return a new object.

00:31:56.466 --> 00:32:02.096 align:middle
But only for cases where the form is
populated without any initial data object.

00:32:02.656 --> 00:32:05.686 align:middle
So when you maybe are creating
a new product or so.

00:32:06.236 --> 00:32:11.606 align:middle
And the names of the properties, uh, the
names of the fields are mapped to the names

00:32:11.606 --> 00:32:19.366 align:middle
of the arguments so you can easily change them,
um, to, to have a different order, something.

00:32:20.416 --> 00:32:22.536 align:middle
Next one, immutable value objects.

00:32:23.086 --> 00:32:31.326 align:middle
So once again, the same code, um, but
we need to create a new object on change

00:32:31.946 --> 00:32:39.266 align:middle
because we can't um change the basic,
uh, the base data object, right?

00:32:39.336 --> 00:32:44.886 align:middle
And um, okay, we already have the
opportunity to define a factory.

00:32:45.076 --> 00:32:50.666 align:middle
So let's just add another option
and let's define it immutable

00:32:50.666 --> 00:32:52.846 align:middle
because that's what we are dealing with here.

00:32:52.846 --> 00:32:55.516 align:middle
Immutable objects and if we set this option

00:32:55.516 --> 00:33:00.356 align:middle
to true every time you submit new
data a new object will be created

00:33:00.476 --> 00:33:06.726 align:middle
and the initial data object that was
bound to the form is still the same

00:33:06.726 --> 00:33:09.136 align:middle
as it was before we were handling the form.

00:33:12.236 --> 00:33:19.906 align:middle
So about the implementation, controller still
looks the same as in the first solution.

00:33:20.476 --> 00:33:27.936 align:middle
The form type is a bit different now
because we have added all these options

00:33:28.036 --> 00:33:34.026 align:middle
that we have shown you before, but that's the
part where we now need to make adjustments.

00:33:34.876 --> 00:33:40.466 align:middle
From the point of view of the model we
are now still using the rich domain model,

00:33:40.466 --> 00:33:44.836 align:middle
which is the main difference
to the first solution

00:33:44.836 --> 00:33:46.676 align:middle
where we were using the anemic domain model.

00:33:47.466 --> 00:33:54.566 align:middle
In the data flow there's not so many
differences here, here the request is coming in

00:33:55.036 --> 00:34:02.076 align:middle
and behind the scenes the important part is now
happening as part of a RichModelFormsBundle.

00:34:02.706 --> 00:34:11.166 align:middle
And the code, um, we had our custom data
mapper implementation before this is now gone

00:34:11.646 --> 00:34:13.916 align:middle
because we have the new bundle.

00:34:14.116 --> 00:34:20.216 align:middle
And the important part here is the switch
or the movement from the right column,

00:34:20.496 --> 00:34:25.626 align:middle
which is what we have to maintain to
the left column, where there is code

00:34:25.746 --> 00:34:31.566 align:middle
that hopefully just works as it is supposed to
do and does not need to be maintained by us.

00:34:31.946 --> 00:34:39.816 align:middle
So, um, we are here and we can now focus again
on our core domain and we don't have to deal

00:34:39.816 --> 00:34:44.486 align:middle
with stuff that is not part of our business.

00:34:45.366 --> 00:34:47.536 align:middle
And well, we are not making
money with it probably.

00:34:53.266 --> 00:34:59.746 align:middle
It generalizes the previous approach of
the data mapper, so behind the scenes, um,

00:34:59.746 --> 00:35:03.286 align:middle
the bundle implements a couple
of data mappers and creepy stuff.

00:35:03.946 --> 00:35:12.996 align:middle
Um, but we have additional data
options form options and um, they are,

00:35:13.766 --> 00:35:20.386 align:middle
the target is using rich domain models so we
can improve, uh, the goal is to improve that

00:35:21.516 --> 00:35:24.976 align:middle
and it's released, but we're
still working on it.

00:35:25.106 --> 00:35:29.396 align:middle
I think you tagged 0.1 yesterday or today.

00:35:29.836 --> 00:35:36.026 align:middle
Yes. Some say there are some installations

00:35:36.026 --> 00:35:42.236 align:middle
on production already, but
I wouldn't do that maybe.

00:35:42.496 --> 00:35:43.306 align:middle
It's not feature complete.

00:35:44.316 --> 00:35:49.456 align:middle
Rich domain models can be very different
because they belong to your domain.

00:35:49.846 --> 00:35:55.426 align:middle
And we just, we just targeted
those cases we came up with.

00:35:55.766 --> 00:35:59.106 align:middle
So maybe you have other targets and use cases

00:35:59.106 --> 00:36:05.356 align:middle
and you could easily share
them with us on GitHub.

00:36:05.356 --> 00:36:10.246 align:middle
That's, that's your part to do
maybe, um, yeah, that's a lie.

00:36:10.616 --> 00:36:17.366 align:middle
But, uh, I don't know the
project, maybe that's not that big.

00:36:17.816 --> 00:36:23.446 align:middle
So it's your turn to help
us give us input about, um,

00:36:23.716 --> 00:36:27.306 align:middle
maybe the namings of the
options and maybe your use cases.

00:36:27.696 --> 00:36:32.266 align:middle
Just maybe just try it in your application
yet, not in production maybe, but,

00:36:32.436 --> 00:36:35.506 align:middle
but on your test server, or on
your local development machine.

00:36:35.506 --> 00:36:41.116 align:middle
Try it out and give us feedback, what
works, what maybe does not work and be nice

00:36:41.546 --> 00:36:44.406 align:middle
and where you need to write
your own glue code once again.

00:36:44.406 --> 00:36:47.226 align:middle
So we want to get rid of the glue code, right?

00:36:48.876 --> 00:36:53.026 align:middle
So, DTOs to sum it up, um,
it's easy to implement,

00:36:53.156 --> 00:36:57.166 align:middle
duplicated validation, it's
additional glue code.

00:36:58.586 --> 00:37:03.346 align:middle
Data mappers, hard to implement, hard to
test, and additional glue code as well.

00:37:03.866 --> 00:37:11.746 align:middle
New Bundle, no glue code on your side, it's
experimental and maybe we can bring some

00:37:11.746 --> 00:37:14.296 align:middle
of those ideas to the core in the future.

00:37:17.066 --> 00:37:17.816 align:middle
Okay, thanks.

00:37:18.646 --> 00:37:18.996 align:middle
That's it.

00:37:19.326 --> 00:37:24.256 align:middle
Thank you.

00:37:25.806 --> 00:37:27.436 align:middle
Three minutes for questions.

00:37:28.326 --> 00:37:30.246 align:middle
Please don't ask hard stuff.

00:37:33.396 --> 00:37:40.766 align:middle
Oh sorry. Does this work?

00:37:42.256 --> 00:37:51.306 align:middle
Hello? Can you go to a slide where you actually
put the data array the exception in and stuff?

00:37:52.006 --> 00:37:53.346 align:middle
Sorry, I don't hear anything.

00:37:53.476 --> 00:37:56.906 align:middle
Can you go to the slide where
you put your extra property paths

00:37:56.906 --> 00:37:59.806 align:middle
and everything in there to the form type?

00:38:00.016 --> 00:38:03.386 align:middle
Um, maybe you can ask the question
without the mic and we'll just repeat it.

00:38:03.386 --> 00:38:08.996 align:middle
I think it's better to understand.

00:38:12.026 --> 00:38:13.106 align:middle
Maybe we can.

00:38:13.236 --> 00:38:14.036 align:middle
No, we cannot.

00:38:14.036 --> 00:38:32.286 align:middle
This one? Yeah.

00:38:32.526 --> 00:39:06.986 align:middle
So the question is if you can
use...You mean for this or for that?

00:39:06.986 --> 00:39:09.286 align:middle
Oh yeah, that's how you use the form component.

00:39:09.286 --> 00:39:10.166 align:middle
That's okay.

00:39:10.166 --> 00:39:25.296 align:middle
Can you repeat the question please?

00:39:25.296 --> 00:39:27.986 align:middle
That's, that's part of the
interface that we cannot change here

00:39:28.246 --> 00:39:30.806 align:middle
because that's coming from the, from the core.

00:39:30.966 --> 00:39:36.396 align:middle
So the question was, do we need to pass
an array here or can we pass an object?

00:39:36.396 --> 00:39:38.516 align:middle
So yeah, that's not, that's not possible.

00:39:38.516 --> 00:39:50.366 align:middle
Yeah. But then we would have
to work around much more stuff.

00:39:50.366 --> 00:39:52.676 align:middle
Yeah, that's probably not what you want to do.

00:39:52.676 --> 00:40:00.916 align:middle
Alright. Christian and I will be around
conference social as well, so see you there.

00:40:00.916 --> 00:40:02.926 align:middle
Thank you.

