0

I'd like to know where to store some custom code which is related to form. I'm writing the Symfony app in which user can add his own category (using form of course). When user add his category the form code inside the controller check if this form is submitted and valid. If yes then user's category and the URI which is creating based on the category name are added to database. Now this whole code and logic is stored in CategoryController inside addCategory() action. Just like the following:

public function addCategory(Request $request): Response
{
    // create the whole form inside CategoryType class
    $form = $this->createForm(CategoryType::class);

    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {

        $categories = $form->getData();
        $categories->setName(preg_replace(
            '#\s+#', ' ', $categories->getName()));

        $categories->setCategoryUri(strtolower(str_replace(
            ' ', '-', $categories->getName())));

        $this->getDoctrine()->getRepository(Categories::class)
            ->addOneCategory($categories);

        return $this->redirectToRoute('flashcard_index');
    }

    return $this->render('category/add_category.html.twig', [
        'form' => $form->createView(),
        'slug' => 'Add category'
    ]);
}

As you see inside the if statement there's code I'm writing about. First, user data are saved to $categories variable, next I'm removing more than one space using preg_replace() (in case the user enter more than one space in form field) and finally I create URI based on category name using strtolower() and str_replace() functions.

The problem is I don't know if storing this above logic inside a controller action is a good practice and if not, where to store this logic? Could you please answer me on that question? Thank you in advance for all answers!

BartTux
  • 29
  • 6
  • 1
    I think you are looking for the form events https://symfony.com/doc/current/form/events.html. That is a way to access the data inside the form. Probably you need the presubmit event. – alexcm Apr 09 '20 at 10:09
  • 1
    It's a trade off between keeping things simple vs keeping things "pure". Yes, controller actions should be kept small but quite a few Symfony apps do put there logic in actions and work just fine. And a bit off-topic perhaps but the regex transformation you have should be handled with a [Data Transformer](https://symfony.com/doc/current/form/data_transformers.html). – Cerad Apr 09 '20 at 12:39
  • Thank you! I'm gonna read about it! – BartTux Apr 10 '20 at 15:43

1 Answers1

1

Then the best place to store the logic is outside your controller like you said. The question you have to ask, is "How can I test my code on the faster and easier way?"

In a separate class. Not a manager class of a thousand line, just one class AddCategorieHandler

If you want to have a decoupled code, remove the data_class from your form. If you want to get the data from your form, just call form->getData() and you will have an array.

Then You could create a message with the symfony messenger component. This message will be associated to an handler AddCategorieHandler.

Bonus, the Messenger component can call doctrine for start a transaction and flush for you.

So..In your controller, you just have to create a message, use the Messenger to dispatch it, and voilà.

And your AddCategorieHandler has all the logic you want, easy to test (no need to mock Doctrine, or functional test..)

If you want to remove a category, just create a DeleteCategoryHandler.

It's a lot of classes you have to create, but in a big project on long term, you will be happy to run your 2,000 tests in 2secs of your entire logic!

Gilles
  • 11
  • 1
  • 1
    Using the messenger component might be a bit of an overkill in this case. The [Event Dispatcher](https://symfony.com/doc/current/event_dispatcher.html) might be a more appropriate choice. – Cerad Apr 09 '20 at 12:35
  • 1
    EventDispatcher is not a good choice...Event can be dispatched everywhere, and be catched by anything. It's not a robust code. Messenger is an example, you can just create your handler without it. On a large project, eventDispatcher is hard. – Gilles Apr 09 '20 at 15:28
  • 1
    Interesting. Messages can also be sent from anywhere and be caught by multiple handlers. Events go back to the original Symfony 2.0 release and are used quite extensively to this very day. Especially by the core. Never heard anyone characterize events as being hard. But to each their own I guess. – Cerad Apr 09 '20 at 16:21
  • Thank you very much guys for your answers! The app is not very big project. In addition to logic described above the app will also contain other types of logic (related or not related to forms). So which of these do you recomend to use in this case? **Messenger** or **Event Dispacher**? Or maybe **Form Events** proposed by alexcm? – BartTux Apr 10 '20 at 15:54
  • Start with a separate class for your logic. Then, try Messenger, and then try event dispatcher. Make your choice! – Gilles Apr 12 '20 at 21:24
  • @Gilles Thanks for answer, I didn't get any notification about your answer... So I should create a new class, put logic to it and then "connect" the form and this class by **Event Dispacher** or **Messenger**. But which directory will be fine to put the seperate class to it? `App/src/Form` or another? What sould the directory structure look like in this case? – BartTux Apr 20 '20 at 08:33