Skip to content

[LiveComponent] Using a DTO for a search form #1850

Open
@YummYume

Description

@YummYume

Hello !

This issue is more like a question that I feel like is not mentioned anywhere in the docs. Traditionally, when making a search form with filters (for example, let's say a global search), I would use a DTO class specially made for that, with each property being an input to the user.

When using a live component, I struggle to find the "right" way to make my component work with a form + a DTO. In the docs, the very first example is a search, but it's using properties directly in the component. Later on, form examples only use entities and show how the submit works with actions, but not how it could work with a simple DTO. The reason I want to use a form in this case is mostly for the ease of use, the already existing form themes, and it would even allow older apps with old searches to be upgraded very easily, by keeping the same DTO.

There are many ways this could be done, for example listen to input events and call an action every time. But I'd like to have it easy, and just have my component automatically re-render when the user types something, or changes a field, and have my DTO update depending on my form. The easiest solution I found was to add 'data-model': 'on(input)|*' to my form, but this causes issues with my DTO in many cases. Here's an example :

class GlobalSearchDTO
{
    public ?string $query = null;
}
#[AsLiveComponent]
class GlobalSearch extends AbstractController
{
    use ComponentWithFormTrait;
    use DefaultActionTrait;

    #[LiveProp]
    public GlobalSearchDTO $globalSearchDTO;

    public function __construct( ) {
        // This is the only way I found to make this "work".
        // Not instantiating the $globalSearchDTO causes an error, obviously
        // Setting it to "null" by default causes the value to never change
        $this->globalSearchDTO = new GlobalSearchDTO();
    }

    public function getResults(): array
    {
        $query = $this->globalSearchDTO->query;
        
       // Get the results...

        return $results;
    }

    protected function instantiateForm(): FormInterface
    {
        return $this->createForm(GlobalSearchType::class, $this->globalSearchDTO);
    }
}
<div {{ attributes }}>
    <div class="flex gap-2.5 items-center">
        {{ form_start(form, {attr: {
            class: 'grow',
            role: 'search',
            'data-model': 'on(input)|*'
        }}) }}
            {# The form... #}
        {{ form_end(form) }}
    </div>

    {# ... #}
</div>

The form itself is a simple form with a simple SearchType for the query.

I'm fairly certain that what I'm doing is a hacky way to get things done, which I don't like. I would love to hear opinions on this and settle on the right approach to get a simple search working with just a DTO and a form.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions