Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filament support #25

Closed
mahfoudfx opened this issue Mar 18, 2023 · 6 comments
Closed

Filament support #25

mahfoudfx opened this issue Mar 18, 2023 · 6 comments

Comments

@mahfoudfx
Copy link

mahfoudfx commented Mar 18, 2023

Hello,
I tried to use this great package with Filament which handles translations using spatie/nova-translatable in a simple way like Laravel Nova, unfortunately this is not working (allowing duplication).

Laravel Nova

Text::make(__('Slug'), 'slug')
  ->creationRules('unique_translation:posts,slug')
  ->updateRules('unique_translation:posts,slug,{{resourceId}}');

Filament (assumed and tested)

Forms\Components\TextInput::make('slug')->required()
  ->rules(['unique_translation:posts,slug']),
  1. Is there any planned release to support Filament?
  2. Awaiting for an official support, what would be the cleanest way to use it with Filament?

Thanks.

@ivanvermeyen
Copy link
Contributor

Hi,

I'm not familiar with Filament.
So I quickly scouted the docs and source for the unique rule, which is similar to unique_translation.
If you know more about its inner workings, I'd be happy to learn it.

It seems that the built-in unique rule accepts an ignorable or ignoreRecord parameter.
This is automatically used on update validations:

https://filamentphp.com/docs/2.x/forms/validation#unique

Sometimes, you may wish to ignore a given model during unique validation. For example, consider an "update profile" form that includes the user's name, email address, and location. You will probably want to verify that the email address is unique. However, if the user only changes the name field and not the email field, you do not want a validation error to be thrown because the user is already the owner of the email address in question.

Field::make('email')->unique(ignorable: $ignoredUser)

If you're using the admin panel, you can easily ignore the current record by using ignoreRecord instead:

Field::make('email')->unique(ignoreRecord: true)

When you look at the code, it evaluates the parameters and generates a standard Rule.

https://github.com/filamentphp/filament/blob/45d8ebce5ff780ba9c270dde890a0b3252d2d537/packages/forms/src/Components/Concerns/CanBeValidated.php#L451-L479

What I don't see is a nice way to add more rules, except with the rule() or rules() method.
But that wouldn't be very clean.

@mahfoudfx
Copy link
Author

I tried to investigate using the simple way similar to Laravel Nova.

Forms\Components\TextInput::make('slug')->required()
  ->rules(['unique_translation:posts,slug']),

It doesn't generate any error but it allows the duplication. After a quick check, I noticed that the generated query is wrong. It is generating the name of the column in place of the code of language.

Actual generated query (not working)

select count(*) as aggregate from `posts` where (`slug` LIKE %"slug": "books"% or `slug` LIKE %"slug":"books"%))

Excpected query

select count(*) as aggregate from `posts` where (`slug` LIKE %"en": "books"% or `slug` LIKE %"en":"books"%))

I found the source of this issue and a solution. It is related to the function getArrayAttributeNameAndLocale located in the class/file UniqueTranslationValidator.php (line 97), by replacing the second parameter of the getAttributeNameAndLocale function. I just replaced the dot '.' by a ',' and it works.

Actual getArrayAttributeNameAndLocale function (not working)

protected function getArrayAttributeNameAndLocale($attribute)
    {
        return $this->getAttributeNameAndLocale($attribute, '.');
    }

Working getArrayAttributeNameAndLocale function

protected function getArrayAttributeNameAndLocale($attribute)
    {
        return $this->getAttributeNameAndLocale($attribute, ',');
    }

@ivanvermeyen
Copy link
Contributor

ivanvermeyen commented Mar 28, 2023

When I change the dot to a comma my validation tests fail.
I do get the correct query using the dot.

Illuminate\Database\Events\QueryExecuted^ {
  +sql: "select count(*) as aggregate from `test_models` where (`slug` LIKE ? or `slug` LIKE ?)"
  +bindings: array:2 [
    0 => "%"en": "existing-slug-en"%"
    1 => "%"en":"existing-slug-en"%"
  ]
  +time: 0.28
  +connection: Illuminate\Database\MySqlConnection^ {#940 …24}
  +connectionName: "mysql"
}

The dot is what Laravel uses to notate array fields in the form.
This package is designed to accept fields like this:

<!-- This assumes you want to use the current locale -->
<input name="slug">

<!-- Specific locales in array syntax -->
<input name="slug[en]">
<input name="slug[nl]">

Can you show me in what format the form input is received?

I think this trait handles the validation:
https://github.com/filamentphp/filament/blob/2.x/packages/support/src/Commands/Concerns/CanValidateInput.php

@ivanvermeyen
Copy link
Contributor

Hi,

I found this:
filamentphp/filament#3110

Does that help?

@dvandal
Copy link
Contributor

dvandal commented Nov 14, 2023

I fixed on my side: #26

@ivanvermeyen
Copy link
Contributor

I fixed on my side: #26

Thank you for the PR! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants