<?php
namespace Social\UserBundle\Form;
use Gedmo\Sluggable\Util\Urlizer;
use Social\UserBundle\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
use Symfony\Component\Validator\Constraints\LessThanOrEqual;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Validator\Context\ExecutionContext;
use Social\FrontendBundle\Form\DataTransformer\LocationToIdTransformer;
use Social\FrontendBundle\Form\DataTransformer\LanguageToIdTransformer;
use DateTime;
use Doctrine\Persistence\ObjectManager;
/**
* Class UserType
*
* @package Social\UserBundle\Form
*/
class UserType extends AbstractType
{
/**
* @var ObjectManager $em
*/
private $em;
/**
* @var TranslatorInterface $translator
*/
private $translator;
/**
* @var string $locale
*/
private $locale;
/**
* UserType constructor.
*
* @param RegistryInterface $registry
* @param TranslatorInterface $translator
* @param string $currentLocale
*/
public function __construct(RegistryInterface $registry, TranslatorInterface $translator,string $currentLocale)
{
$this->em = $registry->getManager();
$this->translator = $translator;
$this->locale = $currentLocale;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->remove('username');
$builder->remove('username_canonical');
$builder->remove('email');
if (in_array('step-1', $options['destination'])) {
$builder
->add(
'username',
TextType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
'autocomplete' => 'off',
'readonly' . ($options['username_disabled'] ? '' : '_') => 'readonly',
],
'property_path' => 'username',
'label_attr' => [
'class' => 'label-hide control-label',
],
'label' => $this->translator->trans('Nickname *'),
'constraints' => new Regex([
'pattern' => "/^(?!(?:[^\d\r\n]*\d){5})[a-zA-Z0-9]{4,15}$/",
'message' => $this->translator->trans('Username invalid'),
]),
]
)
->add(
'email',
TextType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray ',
'autocomplete' => 'off',
'readonly' . ($options['email_disabled'] ? '' : '_') => 'readonly',
],
'label' => $this->translator->trans('Email *'),
'label_attr' => [
'class' => 'label-hide control-label',
],
]
)
->add(
'password',
PasswordType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
'autocomplete' => 'off',
],
'label_attr' => [
'class' => 'label-hide control-label',
],
'label' => $this->translator->trans('Password *'),
'property_path' => 'plainPassword',
'data' => '',
]
)
->add(
'gender',
ChoiceType::class,
[
'choices' => User::$genderOptions,
'required' => true,
'expanded' => true,
'multiple' => false,
'constraints' => [],
'choice_attr' => function ($val, $key, $index) {
return [
'data-toggle' => 'tooltip',
'data-original-title' => User::$genderOptionsAlternative[$key],
'data-placement' => 'top',
];
},
]
);
if ($options['email_repeat']) {
$builder
->add(
'email_repeat',
TextType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
'autocomplete' => 'off',
],
'label_attr' => [
'class' => 'label-hide control-label',
],
'label' => 'Email Repeat *',
'constraints' => [
new Email(['message' => $this->translator->trans('Re-Entered Email is not valid')]),
new NotBlank(['message' => $this->translator->trans('Re-Entered Email should not be blank')]),
],
]
);
}
if ($options['password_repeat']) {
$builder
->add(
'password_repeat',
PasswordType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
'autocomplete' => 'off',
],
'label_attr' => [
'class' => 'label-hide control-label ',
],
'label' => $this->translator->trans('Password Repeat *'),
'property_path' => 'plainPasswordRepeat',
'data' => '',
]
);
}
}
if (in_array('step-3', $options['destination'])) {
$builder
->add(
'new_location',
HiddenType::class,
[
'attr' => [
'class' => 'fake-location-input',
],
'label' => $this->translator->trans('Location *'),
'constraints' => [
new NotNull(['message' => $this->translator->trans('Location is not valid. Please select a valid location')]),
],
]
)
->add(
'fake_country',
HiddenType::class,
['attr' => ['class' => 'fake-country-input']]
)
->add(
'country',
TextType::class,
[
'attr' => [
'class' => $this->getLocationClass('country', $options['data']),
'autocomplete' => 'off',
'placeholder' => 'Country',
]
]
)
->add(
'city',
TextType::class,
[
'attr' => [
'class' => $this->getLocationClass('city', $options['data']),
'autocomplete' => 'off',
'placeholder' => 'City',
]
]
)
->add('delete_profile_picture_id', HiddenType::class)
->add(
'relationship_status',
ChoiceType::class,
[
'choices' => User::getRelationshipStatusOptions($options['locale']),
'attr' => ['class' => 'label-over form-control bg-gray select-fancy'],
]
);
$builder->get('new_location')->addModelTransformer(new LocationToIdTransformer($this->em));
}
if (in_array('set-password', $options['destination'])) {
$builder->add(
'password',
PasswordType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
'autocomplete' => 'off',
],
'label_attr' => [
'class' => 'label-hide control-label',
],
'label' => $this->translator->trans('Password *'),
'property_path' => 'plainPassword',
'data' => '',
'constraints' => [
new NotNull([
'message' => $this->translator->trans('Password should not be empty'),
]),
],
])
->add(
'password_repeat',
PasswordType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
'autocomplete' => 'off',
],
'label_attr' => [
'class' => 'label-hide control-label ',
],
'label' => $this->translator->trans('Password Repeat *'),
'property_path' => 'plainPasswordRepeat',
'data' => '',
]
);
}
if ($options['include_birthday']) {
$builder
->add(
'birthday',
BirthdayType::class,
[
'widget' => 'single_text',
'format' => 'dd/MM/yyyy',
'attr' => [
'class' => 'label-over form-control bg-gray birthday-datepicker',
'autocomplete' => 'off',
],
'label_attr' => [
'class' => 'label-hide control-label',
],
'label' => 'Birthday *',
'invalid_message' => $this->translator->trans('Birthday is not valid.'),
'constraints' => [
new NotNull([
'message' => $this->translator->trans('Birthday should not be blank'),
'groups' => ['Default', 'Profile'],
]),
new LessThanOrEqual(
[
'message' => $this->translator->trans('The minimum registration age is 18 years old'),
'groups' => ['Default', 'Profile'],
'value' => (new DateTime('@' . strtotime('-18 years'))),
]
),
new GreaterThanOrEqual(
[
'message' => $this->translator->trans('The maximum registration age is 90 years old'),
'groups' => ['Default', 'Profile'],
'value' => (new DateTime('@' . strtotime('-90 years'))),
]
),
],
]
);
}
if (in_array('personalize', $options['destination'])) {
$builder
->add('workplace', TextType::class, ['attr' => ['class' => 'label-over form-control bg-gray']])
->add('short_bio', TextareaType::class, ['attr' => ['class' => 'label-over form-control bg-gray']])
->add(
'interested_in',
ChoiceType::class,
[
'choices' => User::getLookingFor($this->locale),
'multiple' => true,
'expanded' => true,
]
)
->add('interested_in_long',
TextareaType::class,
['attr' => ['class' => 'label-over form-control bg-gray interested-in']])
->add('motto', TextType::class, ['attr' => ['class' => 'label-over form-control bg-gray']])
->add('public_profile', CheckboxType::class);
}
if (in_array('notifications', $options['destination'])) {
$builder
->add('receive_email_notifications',
CheckboxType::class,
['label' => $this->translator->trans('Receive email notifications entirely')]);
}
if (in_array('names', $options['destination'])) {
$builder
->add(
'first_name',
TextType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
],
'label_attr' => [
'class' => 'label-hide control-label',
],
'constraints' => [],
]
)
->add(
'last_name',
TextType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
],
'label_attr' => [
'class' => 'label-hide control-label',
],
'constraints' => [],
]
);
}
if (in_array('profile-confirmation', $options['destination'])) {
$builder
->add(
'username',
TextType::class,
[
'attr' => [
'class' => 'label-over form-control bg-gray',
'autocomplete' => 'off',
'readonly' . ($options['username_disabled'] ? '' : '_') => 'readonly',
],
'label_attr' => [
'class' => 'label-hide control-label',
],
'label' => $this->translator->trans('Nickname *'),
'constraints' => new Regex([
'pattern' => "/^(?!(?:[^\d\r\n]*\d){5})[a-zA-Z0-9]{4,15}$/",
'message' => $this->translator->trans('Username invalid'),
]),
'property_path' => 'username',
]
)
->add(
'birthday',
BirthdayType::class,
[
'widget' => 'single_text',
'format' => 'dd/MM/yyyy',
'attr' => [
'class' => 'label-over form-control bg-gray birthday-datepicker',
'autocomplete' => 'off',
],
'label_attr' => [
'class' => 'label-hide control-label',
],
'label' => 'Birthday *',
'invalid_message' => $this->translator->trans('Birthday is not valid.'),
'constraints' => [
new NotNull([
'message' => $this->translator->trans('Birthday should not be blank'),
'groups' => ['Default', 'Profile'],
]),
new LessThanOrEqual(
[
'message' => $this->translator->trans('The minimum registration age is 18 years old'),
'groups' => ['Default', 'Profile'],
'value' => (new DateTime('@' . strtotime('-18 years'))),
]
),
new GreaterThanOrEqual(
[
'message' => $this->translator->trans('The maximum registration age is 90 years old'),
'groups' => ['Default', 'Profile'],
'value' => (new DateTime('@' . strtotime('-90 years'))),
]
),
],
]
);
}
if ($options['include_language']) {
$builder->add(
'language',
ChoiceType::class,
[
'choices' => $options['languages'],
'attr' => ['class' => 'label-over form-control bg-gray select-fancy'],
]
);
$builder->get('language')->addModelTransformer(new LanguageToIdTransformer($this->em));
}
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$postDataValidation = new Callback(
function ($data, ExecutionContext $context) {
$password = $data->getPlainPassword();
$passwordRepeat = $data->getPlainPasswordRepeat();
$gender = $data->getGender();
if ($password != $passwordRepeat && !is_null($data->getId())) {
$context
->buildViolation('Passwords should match')
->atPath('plainPassword')
->addViolation();
}
$username = $data->getUsername();
if (is_null($gender) || !in_array($gender, array_values(User::$genderOptions))) {
$context->addViolation($this->translator->trans('Please select a gender'));
}
if ($data->getId() && count($data->getInterestedIn()) == 0) {
$context->buildViolation('Please select at least 1 gender you are interested in.')
->atPath('interested_in')
->addViolation();
}
}
);
$resolver->setDefaults([
'data_class' => User::class,
'cascade_validation' => true,
'error_bubbling' => true,
'constraints' => [$postDataValidation],
'validation_groups' => ['Default', 'Profile'],
'destination' => ['step-1'],
'include_birthday' => false,
'include_agree' => false,
'email_repeat' => true,
'password_repeat' => false,
'email_disabled' => false,
'username_disabled' => false,
'include_language' => false,
'locale' => 'it',
'languages' => []
]);
}
/**
* @return string
*/
public function getName(): string
{
return 'social_userbundle_usertype';
}
private function getLocationClass($field, $value)
{
$class = "form-control bg-gray location-autocomplete-{$field}";
$className = "get".ucfirst($field);
if (empty($value->$className())) {
return $class;
}
return "$class valid-location";
}
}