-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Add support for php 8.1 enums for choice field #4988
Conversation
issue: #4989 |
Because of doctrine limitations work only with this kind of enums: enum Status:string
{
case WAITING = 'waiting';
case ERROR = 'error';
} and NOT with enum Status
{
case WAITING;
case ERROR;
} |
Since Symfony has EnumType we can do it like this (workaround): // for index because of array_flip
ChoiceField::new('packingType')
->onlyOnIndex()
->setChoices(function () {
$choices = array_map(static fn (?PackingUnit $unit) => [$unit->value => $unit->name], PackingUnit::cases());
return array_merge(...$choices);
})
->setFormType(EnumType::class)
->setFormTypeOption('class', PackingUnit::class)
->setFormTypeOption('choice_label', function (PackingUnit $enum) {
return $enum->value;
}),
// for form
ChoiceField::new('packingType')
->onlyOnForms()
->setChoices(function () {
$choices = array_map(static fn (?PackingUnit $unit) => [$unit->value => $unit], PackingUnit::cases());
return array_merge(...$choices);
})
->setFormType(EnumType::class)
->setFormTypeOption('class', PackingUnit::class)
->setFormTypeOption('choice_label', function (PackingUnit $enum) {
return $enum->value;
}), |
@oleg-andreyev didn't work for me... |
@ERuban updated my workaround. |
}); | ||
} else { | ||
$choices = array_reduce($choices, function ($elements, $enum) { | ||
return $elements + [$enum->value => $enum->value]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Symfony uses enums as name => value
in forms
For me this fixes it for all pages (with the current implementation) $choiceField = ChoiceField::new('status')
->setChoices(Status::cases())
->setFormType(EnumType::class)
->setFormTypeOption('class', Status::class)
;
if (in_array($pageName, [Crud::PAGE_INDEX, Crud::PAGE_DETAIL], true)) {
$choiceField->setChoices(array_reduce(
Status::cases(),
static fn (array $choices, Status $status) => $choices + [$status->name => $status->value],
[],
));
}
yield $choiceField; |
A couple of the workarounds here work, but cause duplication if the key matches the value. e.g.
Results in:
|
@javiereguiluz please, take a look on this |
it looks nice for me, but it is not possible to use the Here is an example: My Enum: enum PageContentType: string
{
case Banner = 'banner';
case Iframe = 'iframe';
case Image = 'image';
case Quote = 'quote';
public function label(): string
{
return match($this)
{
self::Banner => 'Bannière',
self::Iframe => 'Iframe (vidéo / map)',
self::Image => 'Image et texte',
self::Quote => 'Citation',
};
}
} And there the Field:
In the first case, The label displayed on the EA select is "Banner" with the value "banner" but I would like to display a specific label (I tried with the function label()) or be able to translate the "Banner" ? Maybe it is an issue related to EnumType itself... EDIT: If I create a "messages.fr.yaml" with We can see the translation. |
Hello What's the status of this PR ? :) it would be very useful, I had to abandon enum for the moment and go for a class with const instead |
One another area, which this PR doesn't address, is the |
92cdf19
to
f492365
Compare
Thanks Tomek! This has been finally merged! I added some tests/docs (934d5e6) but it'd be great if more people could test this in real apps before tagging a new release. Thanks! |
Thanks, it works, add PR #5610 with some php-cs-fixer and PHP < 8.1 issues |
Hi, Controller: Before this last release I've used it like that: The problem is that wen I use ChoiceType symfony can't convert Enum value because I don't use EnumType. |
Same problem. It can be solve in your entity by changing the getter method #[ORM\Column(type: 'string', length: 10, enumType: UserType::class, name: "user_type")]
private ?UserType $type = null;
public function getTypeEnum(): ?UserType
{
return $this->type;
}
public function getType(): ?string
{
return $this->type?->value;
}
public function setType($type): self
{
if(!$type instanceof UserType ) {
$type= UserType::from($type);
}
$this->type = $type;
return $this;
} |
There is no point to use Enum and return string. I think the best will be to adapt ChoiceField to use EnumType. |
I don't say it's the solution. I just put here my quickest solution i used (it can help someone). |
@abozhinov thanks for reporting this. I'd need your help to solve it. I've created #5620 but I'm not sure if it's the right fix. Thanks. |
@javiereguiluz the issue is that ChoiceType can't convert Enum to String. I think we should create new EnumField to move the logic from ChoiceField to the new field type. |
I have the same problem. +1 for a new dedicated |
Well, I decided this as a workaround for the current 4.x branch. <?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
<entity name="Ksn135\CompanyBundle\Entity\DocSetting">
...
<field name="type" type="string" length="20" nullable="false" enum-type="Ksn135\CompanyBundle\Enums\DocType" />
...
</entity>
</doctrine-mapping> enum DocType: string
{
case INDIVIDUAL = 'individual';
case TYPICAL = 'typical';
public static function choices(): array
{
return [
'admin_label.enum.docType.' . self::INDIVIDUAL->value => self::INDIVIDUAL->name,
'admin_label.enum.docType.' . self::TYPICAL->value => self::TYPICAL->name,
];
}
} class DocSettingCrudController extends AbstractCrudController
{
...
public function createEditFormBuilder(EntityDto $entityDto, KeyValueStore $formOptions, AdminContext $context): FormBuilderInterface
{
$builder = parent::createEditFormBuilder($entityDto, $formOptions, $context);
$builder->get('type')->addModelTransformer(
new CallbackTransformer(
static fn(mixed $value): mixed => $value, // no convertion
static fn(?string $value): ?DocType => DocType::tryFrom($value)
)
);
return $builder;
}
public function configureFields(string $pageName): iterable
{
return [
...
Fields\ChoiceField::new ('type', 'admin_label.doc.field.type')->setRequired(true)
->setFormType(EnumType::class)
->setFormTypeOption('class', DocType::class)
->setFormTypeOption('choice_label', static fn($choice): ?string => 'admin_label.enum.docType.' . strtolower($choice))
->setFormTypeOption('choice_value', static fn($choice): ?string => $choice instanceof \BackedEnum ? $choice->value : $choice)
->setChoices(\in_array($pageName, [Crud::PAGE_INDEX, Crud::PAGE_DETAIL], true) ? DocType::choices() : DocType::cases())
...
];
}
} # messages.en.yaml
admin_label:
enum:
docType:
individual: The Individual
typical: Very typical |
I found a solution. Check my PR -> #5640 |
Proposed change allows to use php 8.1 enum in choice field:
if we have enum in entity:
then we can in configureFields:
without that change in the case of enums we got the error "Warning: array_flip(): Can only flip string and integer values, entry skipped" there: