Easyadminbundle: How can I work with DDD model?

Created on 3 Dec 2017  路  8Comments  路  Source: EasyCorp/EasyAdminBundle

I tried to use DDD model "Tag" with 3 fields: id, name, hash. "Tag" gets them in constructor. There are no setters at all, only getters (may be named a different way like $tag->name()). "Hash" field is auto-generated, so it should miss in form, it is generated in constructor.
Is it possible to work without getters/setter with non-empty constructor and dependencies in some methods (e.g. $tag->changeName(string $name, TransliteratorInterface $transliterator)) saving easyadmin templating? I found hardcoded "new $entity()", then i tried to override everything:

  1. extended AdminController to override createNewTagEntity() returning null.
  2. added custom controller to Tag entity in easy_admin.yaml
  3. created custom TagType extended from EasyAdminFormType
  4. implemented DataMapperInterface and overwrote buildForm() & configureOptions() functions:
public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->setDataMapper($this);
        parent::buildForm($builder, $options);
    }

public function configureOptions(OptionsResolver $resolver)
    {
        parent::configureOptions($resolver);

        $resolver->setDefaults(array(
            'data_class' => Tag::class,
            'empty_data' => null
        ));
    }

public function configureOptions(OptionsResolver $resolver)
    {
        parent::configureOptions($resolver);

        $resolver->setDefaults(array(
            'data_class' => Tag::class,
            'empty_data' => null
        ));
    }

    public function mapDataToForms($data, $forms)
    {
        $forms = iterator_to_array($forms);
        $forms['id']->setData($data ? $data->id : null);
        $forms['name']->setData($data ? $data->getName() : null);
    }

The point I created the issue - it doesn't work. It causes many different errors, including missing of 'view' and 'entity' keys in buildForm() options that I failed to add even through custom TypeConfigurator. So, is there any way to work with DDD models correctly with overrides or requesting new feature? DDD models are not something magical, it is the only correct way to work with Doctrine: Doctrine Best Practices

feature wontfix

All 8 comments

It's hart to give you a answer without exact bug description (many different errors?). You can work with DDD-Entities in EasyAdmin, but not out of the box. Please give us some example code, so we can help you.

I'm really sorry but I can't help you in any way because I don't use DDD. @fadoe says that you can do DDD with this bundle, but it requires some changes, so I guess that EasyAdmin is not prepared for DDD. I'm sorry!

One of my main interrogatives is:
_Would EasyAdmin be able to work on the Doctrine entities without having setters/getters on them?_


DDD mostly rejects setters/getters in objects because they have no value; the public interface of the object should just provide methods that have business/domain value (e.g. User::promoteToVip() rather that a too-technical User::setPromote('vip'); or User::canBePromoted() rather than a `if ($user->getPromote() === true)麓 [not the best examples though]).

Doctrine will ignore setters/getters/constructor and will use just reflection, allowing to use the entity with any preferred paradigm.

is this now possible with easyadmin 3.x? after reading #3069 i fear not :(

would love to be able to use easyadmin with entities which have to be valid after constuction time (which requires a correct id value which is not null).

just trying to follow the doctrine best practices from @ocramius

Entity Validity

  • Entities should always be valid
  • Stay Valid after __construct

https://www.youtube.com/watch?v=WW2qPKukoZY&t=962
https://cdn.rawgit.com/Ocramius/doctrine-best-practices/framework-days-2016/index.html#/48

Avoid Setters
https://www.youtube.com/watch?v=WW2qPKukoZY&t=1101
https://cdn.rawgit.com/Ocramius/doctrine-best-practices/framework-days-2016/index.html#/54

from talk at PHP Frameworks Day 2016 - Doctrine Best Practices
https://fwdays.com/en/event/php-frameworks-day-2016/review/doctrine


anyone has experience with DDD entities and easyadmin 3.x? if yes it would be awesome to contribute it here, some doc would be for this would be awesome.

On #2403 there are more insights and discussions.

Basically:

  • keep domain separated
  • validate inside constructor they way you prefer (manual validation; or based on Symfony Validator; or based on events; I prefer a more purist approach rather than tie the domain code to infrastructure/environment specific dependencies)
  • EasyAdmin is based on Symfony Forms; forms follows the assumption that the data submitted can be invalid, hence you cannot use an always-valid entity; you need to be able to provide an emtpy entity.

    • from that follows that you should use DTOs, rather than entities, in the context of Symfony Forms. Unfortunately that's quite some tangling (at least in EA < 3) with that component, so you need to override the AdminControllerTrait to not generate Entities but rather DTOs, before working with forms (so in the default CRUD actions); or simple arrays I think might also be used (or something that resembles them).

      Unfortunately EA 3.x has changed a lot and the AdminControllerTrait is not there anymore, so you need to check where that logic has been moved (I didn't do it yet).

I try to keep the Domain namespace separated by the App/implementation namespace, use interfaces everywhere.

_[EDIT]_
About validation, might be worthy to understand what validation is business validation and what is data validation. Data validation should be in the context of Forms and of your App. While Domain/Business validation should be carried over in a way independent from the framework/infrastructure used; iirc the Specification Pattern is a good way to do it.
_[/EDIT]_

Note: my experience is just in structuring for future change to DDD paradigms; I didn't yet implement always-valid entities (since the project started following the usual Entity|DTO structure with setters) so I didn't try yet the whole Forms+DTO & Domain+Entities option.
Also, I am not looking in the topic since some months, and I didn't read again the PR that I linked; but iirc there there was quite some insights from the maintainers about how to implement DDD in EA.

Of course in case you achieve or find out something, would be great if you could share it 馃檭

@Pictor13 You are right: DDD and CRUD are not always good with each other, but if one ultimately needs to mix them up to fasten development by using EasyAdmin, then the DTO approach is the easiest and best option.

However, EasyAdmin will never support DTOs.

I made some proofs of concepts of DTOs handling in the past for EasyAdmin version 1 and 2, and I'm actually using them in 2 projects in production and they're fine (and they comply very well with the TranslatableEntity extension, by the way).
I could make a package of this PoC if people need it, there's a working one in this project for showcase (and it has translatable config).
However, this is for EasyAdmin 2 only.

Since EasyAdmin 3 changed almost everything, my implementation is obsolete and cannot be ported to v3, so we would have to reverse engineer the entire new implementation and see how we can "plug" into it to add easier support for DTOs.

@Pictor13 if you really need to work with DTOs, it's better to not use this bundle. We don't provide support, so you'll get frustrated about how hard it's to make anything work. You may try to work with other admin bundles (e.g. Sonata Admin) ... or even implement your own solution from scratch (this is usually the worst option ... except when your needs are custom/special, which can be easier to develop from scratch than make an existing bundle adapt to your needs).

Thanks for the suggestion; I understand your point.

My main concern is about a project that I started with EA2 last year; unfortunately it's too late to switch bundle/framework now. That's the reason why I insisted. But that is what it is.
At least I can confirm that I need to avoid to upgrade that project to EA3, in order to avoid breaking the DDD that I implemented till now.

You suggestion makes total sense for the next projects, tho.
In any case, thanks for updating us, and for taking the time to decide and give a clear answer in #3203 .
I added a personal remarks there, that I think might improve the situation, if you want to give a look 馃檪

Was this page helpful?
0 / 5 - 0 ratings