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

Amélioration des perfs UpdateMeasureController #1124

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ framework:
#fragments: true
php_errors:
log: true
validation:
cache: validator.mapping.cache.adapter

http_client:
scoped_clients:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,49 @@
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
<class name="App\Application\Regulation\Command\Location\SaveLocationCommand">
<property name="roadType">
<constraint name="NotBlank" />
<constraint name="NotBlank">
<option name="groups">
<value>Default</value>
</option>
</constraint>
</property>

<property name="namedStreet">
<constraint name="Valid" />
<constraint name="Valid">
<option name="groups">
<value>lane</value>
</option>
</constraint>
</property>

<property name="departmentalRoad">
<constraint name="Valid" />
<constraint name="Valid">
<option name="groups">
<value>departmentalRoad</value>
</option>
</constraint>
</property>

<property name="nationalRoad">
<constraint name="Valid" />
<constraint name="Valid">
<option name="groups">
<value>nationalRoad</value>
</option>
</constraint>
</property>

<property name="rawGeoJSON">
<constraint name="Valid" />
<constraint name="Valid">
<option name="groups">
<value>rawGeoJSON</value>
</option>
</constraint>
</property>
<constraint name="App\Infrastructure\Validator\SaveLocationCommandConstraint" />

<constraint name="App\Infrastructure\Validator\SaveLocationCommandConstraint">
<option name="groups">
<value>Default</value>
</option>
</constraint>
</class>
</constraint-mapping>
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,9 @@ public function getRoadDeleteCommand(): ?CommandInterface

return null;
}

public function getRoadType(): string
{
return $this->roadType;
}
}
212 changes: 142 additions & 70 deletions src/Infrastructure/Form/Regulation/LocationFormType.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,98 +12,170 @@
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class LocationFormType extends AbstractType
{
private const FORM_FIELDS = [
'departmentalRoad' => NumberedRoadFormType::class,
'nationalRoad' => NumberedRoadFormType::class,
'namedStreet' => NamedStreetFormType::class,
'rawGeoJSON' => RawGeoJSONFormType::class,
];

private const ROAD_TYPE_TO_FORM_FIELD = [
RoadTypeEnum::DEPARTMENTAL_ROAD->value => 'departmentalRoad',
RoadTypeEnum::NATIONAL_ROAD->value => 'nationalRoad',
RoadTypeEnum::LANE->value => 'namedStreet',
RoadTypeEnum::RAW_GEOJSON->value => 'rawGeoJSON',
];

public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add(
'roadType',
ChoiceType::class,
options: $this->getRoadTypeOptions(),
)
->add(RoadTypeEnum::DEPARTMENTAL_ROAD->value, NumberedRoadFormType::class, [
'roadType' => RoadTypeEnum::DEPARTMENTAL_ROAD->value,
'administrators' => $options['administrators'][RoadTypeEnum::DEPARTMENTAL_ROAD->value],
'label' => false,
])
->add(RoadTypeEnum::NATIONAL_ROAD->value, NumberedRoadFormType::class, [
'roadType' => RoadTypeEnum::NATIONAL_ROAD->value,
'administrators' => $options['administrators'][RoadTypeEnum::NATIONAL_ROAD->value],
'label' => false,
])
->add('namedStreet', NamedStreetFormType::class, [
'label' => false,
$this->addRoadTypeChoice($builder, $options['permissions'])
->addSubForms($builder, $options['administrators'])
->addFormEventListeners($builder);
}

public function configureOptions(OptionsResolver $resolver): void
{
$resolver
->setDefaults([
'data_class' => SaveLocationCommand::class,
'administrators' => $this->getDefaultAdministrators(),
'permissions' => [],
'validation_groups' => $this->getValidationGroups(),
])
->add('rawGeoJSON', RawGeoJSONFormType::class, [
->setAllowedTypes('administrators', 'array')
->setAllowedTypes('permissions', 'array');
}

private function addRoadTypeChoice(FormBuilderInterface $builder, array $permissions): self
{
$builder->add('roadType', ChoiceType::class, [
'choices' => $this->getRoadTypeChoices($permissions),
'label' => 'regulation.location.type',
'label_attr' => ['class' => 'required'],
]);

return $this;
}

private function addSubForms(FormBuilderInterface $builder, array $administrators): self
{
foreach (self::FORM_FIELDS as $field => $formType) {
$options = [
'mapped' => false,
'label' => false,
])
;

$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
$form = $event->getForm();
$command = $event->getData();

$isRawGeoJSON = $command?->roadType === RoadTypeEnum::RAW_GEOJSON->value;
$canUseRawGeoJSON = \in_array(CanUseRawGeoJSON::PERMISSION_NAME, $options['permissions']);

if ($isRawGeoJSON || $canUseRawGeoJSON) {
// Replace field with new options
$form->add(
'roadType',
ChoiceType::class,
options: $this->getRoadTypeOptions(
includeRawGeoJSONOption: true,
),
);
];

if ($formType === NumberedRoadFormType::class) {
$roadType = str_contains($field, 'departmental')
? RoadTypeEnum::DEPARTMENTAL_ROAD->value
: RoadTypeEnum::NATIONAL_ROAD->value;

$options += [
'roadType' => $roadType,
'administrators' => $administrators[$roadType] ?? [],
];
}
});

$builder->add($field, $formType, $options);
}

return $this;
}

private function getRoadTypeOptions(bool $includeRawGeoJSONOption = false): array
private function addFormEventListeners(FormBuilderInterface $builder): self
{
$choices = [];
$choiceAttr = [];
$builder
->addEventListener(
FormEvents::PRE_SET_DATA,
fn (FormEvent $event) => $this->onPreSetData($event),
)
->addEventListener(
FormEvents::PRE_SUBMIT,
fn (FormEvent $event) => $this->onPreSubmit($event),
);

foreach (RoadTypeEnum::cases() as $case) {
$label = \sprintf('regulation.location.road.type.%s', $case->value);
return $this;
}

if ($case->value === RoadTypeEnum::RAW_GEOJSON->value && !$includeRawGeoJSONOption) {
$choiceAttr[$label] = [
'hidden' => '',
'disabled' => 'disabled', // For Safari (it does not support <option hidden>)
];
private function onPreSetData(FormEvent $event): void
{
$data = $event->getData();
if (!$data) {
return;
}

$this->updateFormMapping($event->getForm(), $data->getRoadType());
}

private function onPreSubmit(FormEvent $event): void
{
$data = $event->getData();
if (!isset($data['roadType'])) {
return;
}

$this->updateFormMapping($event->getForm(), $data['roadType']);
}

private function updateFormMapping(FormInterface $form, string $roadType): void
{
// Reset all mappings to false
foreach (self::FORM_FIELDS as $field => $formType) {
$this->updateFormField($form, $field, false);
}

// Set the active form mapping to true
if ($activeField = self::ROAD_TYPE_TO_FORM_FIELD[$roadType] ?? null) {
$this->updateFormField($form, $activeField, true);
}
}

private function updateFormField(FormInterface $form, string $field, bool $mapped): void
{
if (!$form->has($field)) {
return;
}

$config = $form->get($field)->getConfig();
$form->add($field, \get_class($config->getType()->getInnerType()), [
'mapped' => $mapped,
'label' => false,
] + $config->getOptions());
}

private function getRoadTypeChoices(array $permissions): array
{
$choices = ['regulation.location.type.placeholder' => ''];

foreach (RoadTypeEnum::cases() as $case) {
if ($case->value === RoadTypeEnum::RAW_GEOJSON->value
&& !\in_array(CanUseRawGeoJSON::PERMISSION_NAME, $permissions, true)) {
continue;
}

$choices[$label] = $case->value;
$choices[\sprintf('regulation.location.road.type.%s', $case->value)] = $case->value;
}

return $choices;
}

private function getDefaultAdministrators(): array
{
return [
'choices' => array_merge(
['regulation.location.type.placeholder' => ''],
$choices,
),
'choice_attr' => $choiceAttr,
'label' => 'regulation.location.type',
'label_attr' => [
'class' => 'required',
],
RoadTypeEnum::DEPARTMENTAL_ROAD->value => [],
RoadTypeEnum::NATIONAL_ROAD->value => [],
];
}

public function configureOptions(OptionsResolver $resolver): void
private function getValidationGroups(): callable
{
$resolver->setDefaults([
'administrators' => [
RoadTypeEnum::DEPARTMENTAL_ROAD->value => [],
RoadTypeEnum::NATIONAL_ROAD->value => [],
],
'permissions' => [],
'data_class' => SaveLocationCommand::class,
]);
$resolver->setAllowedTypes('administrators', 'array');
$resolver->setAllowedTypes('permissions', 'array');
return static function (FormInterface $form): array {
return ['Default', $form->getData()?->getRoadType() ?? ''];
};
}
}
Loading