Add Terms and Conditions and marketing opt-in checkboxes to registration

Registration now requires agreeing to the Terms and Conditions and lets
users opt in to hear about future projects. The opt-in is persisted on
the user via a new marketing_opt_in column (migration included).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Frank
2026-07-04 20:28:52 +02:00
co-authored by Claude Sonnet 5
parent 703d2af3d8
commit ec34a1ddb9
4 changed files with 56 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260704160000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add marketing_opt_in column to user table';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE `user` ADD marketing_opt_in TINYINT(1) NOT NULL DEFAULT 0');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE `user` DROP marketing_opt_in');
}
}
+15
View File
@@ -39,6 +39,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column(type: 'boolean')] #[ORM\Column(type: 'boolean')]
private bool $isVerified = false; private bool $isVerified = false;
#[ORM\Column(type: 'boolean')]
private bool $marketingOptIn = false;
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
@@ -137,4 +140,16 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
public function isMarketingOptIn(): bool
{
return $this->marketingOptIn;
}
public function setMarketingOptIn(bool $marketingOptIn): static
{
$this->marketingOptIn = $marketingOptIn;
return $this;
}
} }
+13
View File
@@ -6,12 +6,14 @@ use App\Tech\Entity\User;
use Karser\Recaptcha3Bundle\Form\Recaptcha3Type; use Karser\Recaptcha3Bundle\Form\Recaptcha3Type;
use Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3; use Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotBlank;
@@ -42,6 +44,17 @@ class RegistrationFormType extends AbstractType
), ),
], ],
]) ])
->add('agreeTerms', CheckboxType::class, [
'mapped' => false,
'label' => 'I agree to the Terms and Conditions',
'constraints' => [
new IsTrue(message: 'You must agree to the Terms and Conditions.'),
],
])
->add('marketingOptIn', CheckboxType::class, [
'required' => false,
'label' => 'Keep me informed about future projects and updates',
])
->add('captcha', Recaptcha3Type::class, [ ->add('captcha', Recaptcha3Type::class, [
'constraints' => new Recaptcha3(), 'constraints' => new Recaptcha3(),
'action_name' => 'registration', 'action_name' => 'registration',
@@ -9,6 +9,8 @@
{{ form_row(registrationForm.email) }} {{ form_row(registrationForm.email) }}
{{ form_row(registrationForm.username) }} {{ form_row(registrationForm.username) }}
{{ form_row(registrationForm.plainPassword) }} {{ form_row(registrationForm.plainPassword) }}
{{ form_row(registrationForm.agreeTerms) }}
{{ form_row(registrationForm.marketingOptIn) }}
{{ form_row(registrationForm.captcha) }} {{ form_row(registrationForm.captcha) }}
<div class="d-grid mt-3"> <div class="d-grid mt-3">