Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,26 @@ class CompanyMemberInvitationType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('email', EmailType::class)
->add('manager', CheckboxType::class, ['required' => false, 'label' => 'Lui partager les droits de gestion'])
// empty_data explicite : TextType le fait valoir null quand le champ n'est pas
// requis, ce qui ferait échouer setEmail(string) sur un email laissé vide.
->add('email', EmailType::class, ['empty_data' => ''])
->add('manager', CheckboxType::class, [
'required' => false,
'label' => 'Lui partager les droits de gestion',
// disabled fait aussi ignorer la valeur soumise au profit de celle du modèle :
// le verrou résiste à un POST forgé.
'disabled' => $options['lock_manager'],
])
;
}

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => CompanyMemberInvitation::class,
'lock_manager' => false,
]);

$resolver->setAllowedTypes('lock_manager', 'bool');
}
}
35 changes: 34 additions & 1 deletion sources/AppBundle/Association/Form/CompanyMemberType.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use AppBundle\Association\CompanyMembership\SubscriptionManagement;
use AppBundle\Association\Model\CompanyMember;
use AppBundle\Association\Model\CompanyMemberInvitation;
use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaType;
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\IsTrue as RecaptchaIsValid;
use Symfony\Component\Form\AbstractType;
Expand All @@ -16,8 +17,12 @@
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class CompanyMemberType extends AbstractType
{
Expand Down Expand Up @@ -87,16 +92,44 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'entry_type' => CompanyMemberInvitationType::class,
'allow_add' => true,
'required' => false,
// Déclaré ici et non sur le modèle : CompanyMember::$invitations n'a pas
// d'Assert\Valid, la validation ne cascade donc pas vers les invitations.
'constraints' => [
new Callback(static function (?array $invitations, ExecutionContextInterface $context): void {
$first = $invitations[0] ?? null;

if ($first instanceof CompanyMemberInvitation && '' !== trim($first->getEmail())) {
return;
}

$context
->buildViolation("L'adresse email du premier membre est obligatoire.")
->atPath('[0].email')
->addViolation()
;
}),
],
])
->add('recaptcha', EWZRecaptchaType::class, [
'label' => 'Vérification',
'label' => false,
'mapped' => false,
'constraints' => [
new RecaptchaIsValid(),
],
])
->add('save', SubmitType::class, ['label' => 'saveMembership'])
;

// Le premier membre est toujours gestionnaire. `entry_options` s'appliquant à toute
// la collection, on reconstruit l'enfant 0 ; priorité négative pour passer après
// ResizeFormListener, qui crée les enfants sur ce même évènement.
$builder->get('invitations')->addEventListener(
FormEvents::PRE_SET_DATA,
static function (FormEvent $event): void {
$event->getForm()->add('0', CompanyMemberInvitationType::class, ['lock_manager' => true]);
},
-1,
);
}

public function configureOptions(OptionsResolver $resolver): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ class CompanyMemberInvitation implements NotifyPropertyInterface

private int $companyId;

// Valeur par défaut : sans elle, getEmail() sur une invitation fraîchement instanciée
// (CompanyAction pré-remplit la collection) lève une erreur de propriété non initialisée.
#[Assert\Email]
private string $email;
private string $email = '';

private string $token;

Expand Down Expand Up @@ -65,7 +67,7 @@ public function getEmail(): string

public function setEmail(string $email): self
{
$this->propertyChanged('email', $this->email ?? null, $email);
$this->propertyChanged('email', $this->email, $email);
$this->email = $email;
return $this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,17 @@ public function __construct(

public function __invoke(Request $request): Response
{
// On pré-remplit autant de lignes que le forfait par défaut en compte, pour que le
// formulaire reste utilisable sans JavaScript. Le script ne sert plus qu'à réagir aux
// changements du select « nombre de membres ».
$defaultMembers = SubscriptionManagement::AFUP_PERSONNE_MORALE_SEUIL;

$data = new CompanyMember();
$data->setInvitations([
new CompanyMemberInvitation()->setManager(true),
]);
$data->setMaxMembers($defaultMembers);
$data->setInvitations(array_map(
static fn(int $index): CompanyMemberInvitation => new CompanyMemberInvitation()->setManager(0 === $index),
range(0, $defaultMembers - 1),
));

$subscribeForm = $this->createForm(CompanyMemberType::class, $data);
$subscribeForm->handleRequest($request);
Expand Down
Loading
Loading