<?php
namespace App\Form\Customer;
use App\Entity\BillingAddress;
use Exception;
use App\Entity\Address;
use App\Entity\Country;
use App\Form\DataTransformer\FilterPhoneTransformer;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Formular pro vykresleni poli entity Address
* Formular ma povinnoy options atribut 'entityManager'
*/
class AddressType extends AbstractType
{
public const TYPE_DELIVERY = 1;
public const TYPE_RETURN = 2;
public const TYPE_BILLING = 3;
public const TYPE_DELIVERY_FRONTEND = 4;
protected TranslatorInterface $translator;
protected FilterPhoneTransformer $filterFormTransformer;
public function __construct(TranslatorInterface $translator, FilterPhoneTransformer $transformer)
{
$this->translator = $translator;
$this->filterFormTransformer = $transformer;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$requiredEmail = false;
$phoneLabel = $this->translator->trans('Telefon');
switch ($options['addressType']) {
case self::TYPE_DELIVERY:
$phoneLabel = $this->translator->trans('Telefon příjemce:');
$builder->add('district', TextType::class, [
'label' => $this->translator->trans('Městská čtvrť:'),
'required' => false,
'attr' => ['minlength' => '2', 'maxlength' => '63']
]);
break;
case self::TYPE_RETURN:
$requiredEmail = true;
break;
case self::TYPE_BILLING:
$options['data_class'] = BillingAddress::class;
$builder
->add('companyName', TextType::class, [
'label' => $this->translator->trans('Název společnosti:'),
'required' => false,
'attr' => ['maxlength' => '60', 'pattern' => '^[a-zA-Z0-9_,\.| ]*$', 'reqStar' => 0]
])
->add('companyRegNumber', TextType::class, [
'label' => $this->translator->trans('IČO:'),
'required' => false,
'attr' => ['maxlength' => '60', 'pattern' => '^[a-zA-Z0-9_,\.| ]*$', 'reqStar' => 0]
])
->add('vatNumber', TextType::class, [
'label' => $this->translator->trans('DIČ:'),
'required' => false,
'attr' => ['maxlength' => '60', 'pattern' => '^[a-zA-Z0-9_,\.| ]*$', 'reqStar' => 0]
]);
break;
case self::TYPE_DELIVERY_FRONTEND:
break;
default:
throw new Exception('Neplatny typ adresy!');
}
$builder
->add('name', TextType::class, [
'label' => $this->translator->trans('Jméno:'),
'required' => true,
'attr' => ['minlength' => '2', 'maxlength' => '60']
])
->add('address1', TextType::class, [
'label' => $this->translator->trans('Ulice a č. p.:'),
'required' => true,
'attr' => ['minlength' => '2', 'maxlength' => '255']
])
->add('address2', TextType::class, [
'label' => $this->translator->trans('Doplňující adresa:'),
'required' => false,
'attr' => ['minlength' => '2', 'maxlength' => '255']
])
->add('city', TextType::class, [
'label' => $this->translator->trans('Město:'),
'required' => true,
'attr' => ['minlength' => '1', 'maxlength' => '255']
])
->add('zipCode', TextType::class, [
'label' => $this->translator->trans('PSČ:'),
'required' => true,
'attr' => ['minlength' => '5', 'maxlength' => '6']
])
->add('phone', TelType::class, [
'label' => $phoneLabel,
'required' => true,
'attr' => ['minlength' => '6', 'maxlength' => '18']
])
->add('email', EmailType::class, [
'label' => $this->translator->trans('E-mail:'),
'required' => $requiredEmail,
'attr' => ['minlength' => '5', 'maxlength' => '60']
]);
/**
* Podle typu formulare se rozhoduji, jeslti:
* - vykresluji do formulare pole select pro Country
* - nic nevykresluji a zemi nastavim na defaultni hodnotu
*/
// pokud uz mam country ve formu predanou (tj. treba v edit address) pouziju ji, jinak ji najdu v db
// dump($builder->getData());
// dd($options);
$address = $builder->getData();
if ($address->getCountry() !== null) {
$country = $address->getCountry();
} else {
$countryRepo = $options['entityManager']->getRepository(Country::class);
$country = $countryRepo->findOneBy(['iso' => $options['countryIso']]);
}
if ($options['renderCountry'] === true) {
// vykresluji select se seznamem zemi, kazdy typ formulare ma sve $countryOptions
$countryOptions = $this->setCountryParams($options);
// pokud znam $country, nastavuji ji vychozi do formu
if ($country !== null) {
$countryOptions['data'] = $country;
}
//pokud mam zvoleny neaktivni select, nastavuji ho neaktivni
if ($options['disabledCountry'] === true) {
$countryOptions['disabled'] = true;
}
$builder->add('country', EntityType::class, $countryOptions);
} else {
// nevykresluji select, rovnou nastavuji vychozi zemi, ktera musi existovat
if ($country === null) {
throw new Exception('Nepodařilo se najít zemi s ISO: "'.$options['countryIso'].'"!');
}
$address = $builder->getData();
$address->setCountry($country);
}
if ($options['renderSubmitButton']) {
$builder->add('submit', SubmitType::class, [
'attr' => ['class' => 'btn btn-success'],
'label' => $this->translator->trans('Odeslat')
]);
}
$builder->get('phone')
->addModelTransformer($this->filterFormTransformer);
}
public function configureOptions(OptionsResolver $resolver): void
{
$required = [];
$required[] = 'entityManager'; // POVINNY ATRIBUT - pri inicializaci formulare
$required[] = 'addressType'; // POVINNY ATRIBUT - pri inicializaci formulare
$required[] = 'renderSubmitButton'; // bool, jestli chci vykreslit tlacitko odeslat
$required[] = 'renderCountry'; // bool jestli chci vykreslovat select s vyberem zemi nebo priradit adrese country podle countryIso
$required[] = 'countryIso'; //iso, ktera zeme se ma ukazovat (pokud ma ale adresa uz nastavenou country, toto nepouziju)
$required[] = 'disabledCountry'; //bool jestli ma byt pole country disabled
$resolver->setRequired($required);
$resolver->setDefaults(
[
'data_class' => Address::class,
'renderSubmitButton' => false,
'countryIso' => 'cz',
'renderCountry' => false,
'disabledCountry' => false
]
);
}
/**
* Medoda nastavuje formulare u adresy pole country podle toho, jeslti chceme sklonovany nebo obycejny select
* pokud je $options['addressType] === 4 (delivery frondend), tak se jedna o SimpleOrderForm na frontendu, vykresluji zeme sklonovane
* pokud je $options['addressType] !== 4 tak vykresluji noramlne zeme z db
* @param array $formOptions options formulare
* @return array options pro form pole country
*/
public function setCountryParams(array $formOptions): array
{
$options = [];
$options['class'] = Country::class;
$options['expanded'] = false;
$options['multiple'] = false;
$options['label'] = $this->translator->trans('Země:');
if ($formOptions['addressType'] === self::TYPE_DELIVERY_FRONTEND) {
$options['choices'] = $formOptions['entityManager']
->getRepository(Country::class)->findActiveCountries();
$options['choice_value'] = static function (Country $c) {
return $c->getIso(); // iso je potreba jako klic ve formulari kvuli ajax pozadavkum na prepocet ceny
};
$options['choice_label'] = function (Country $c) {
return $this->translator->trans(
'send_package',
['country_iso' => $c->getIso(), 'case' => 2], // v formulari ukazuji prelozene zeme
'messages'
);
};
} else {
$options['query_builder'] = static function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.name', 'ASC');
};
$options['choice_label'] = 'name';
}
return $options;
}
}