Skip to content

Instantly share code, notes, and snippets.

@migmolrod
Last active July 3, 2019 09:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save migmolrod/1dbad05afc58974f7b938ab67a36b132 to your computer and use it in GitHub Desktop.
Save migmolrod/1dbad05afc58974f7b938ab67a36b132 to your computer and use it in GitHub Desktop.
Nested property validation? For a lack of a better name
<?php
declare(strict_types=1);
namespace App\Entity;
/**
* @ORM\Entity()
* @ORM\Table(name="app_business")
*/
class Business implements BusinessInterface
{
use ContactAwareTrait;
// [ other properties and getters/setters ]
}
{{ form_errors(form) }}
{#
[ other form fields which are correctly validated, showing the error bubbles
next to the corresponding invalid field ]
#}
{{ form_row(form.contact) }}
{#
if any of the contact subfields has an error, the error bubble is shown
at the start of the form, instead of next to each field
#}
<?php
declare(strict_types=1);
namespace App\Form\Type;
use App\Entity\User\ShopUser;
use Sylius\Bundle\ResourceBundle\Form\EventSubscriber\AddCodeFormSubscriber;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Sylius\Bundle\ResourceBundle\Form\Type\ResourceTranslationsType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
class BusinessType extends AbstractResourceType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// [ other form fields ]
->add('contact', ContactType::class)
// I've tried adding the `'error_bubbling' => false,` option here, but no luck :(
// [ other form fields ]
;
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'app_business';
}
}
{% block app_contact_widget %}
<div class="two fields">
{{ form_row(form.phone) }}
{{ form_row(form.mobile) }}
</div>
<div class="two fields">
{{ form_row(form.email) }}
{{ form_row(form.fax) }}
</div>
{% endblock %}
<?php
declare(strict_types=1);
namespace App\Model;
use Doctrine\ORM\Mapping as ORM;
trait ContactAwareTrait
{
/**
* @var string|null
* @ORM\Column(type="string", length=24, nullable=true)
*/
protected $phone;
/**
* @var string|null
* @ORM\Column(type="string", length=24, nullable=true)
*/
protected $mobile;
/**
* @var string|null
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $email;
/**
* @var string|null
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $fax;
/**
* @return string|null
*/
public function getPhone(): ?string
{
return $this->phone;
}
/**
* @param string|null $phone
*/
public function setPhone(?string $phone): void
{
$this->phone = $phone;
}
/**
* @return string|null
*/
public function getMobile(): ?string
{
return $this->mobile;
}
/**
* @param string|null $mobile
*/
public function setMobile(?string $mobile): void
{
$this->mobile = $mobile;
}
/**
* @return string|null
*/
public function getEmail(): ?string
{
return $this->email;
}
/**
* @param string|null $email
*/
public function setEmail(?string $email): void
{
$this->email = $email;
}
/**
* @return string|null
*/
public function getFax(): ?string
{
return $this->fax;
}
/**
* @param string|null $fax
*/
public function setFax(?string $fax): void
{
$this->fax = $fax;
}
/**
* @return array
*/
public function getContact(): array
{
return [
'phone' => $this->getPhone(),
'mobile' => $this->getMobile(),
'email' => $this->getEmail(),
'fax' => $this->getFax(),
];
}
/**
* @param array $contact
*/
public function setContact(array $contact): void
{
$this->setPhone($contact['phone']);
$this->setMobile($contact['mobile']);
$this->setEmail($contact['email']);
$this->setFax($contact['fax']);
}
}
<?php
declare(strict_types=1);
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ContactType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
$options['phone']['name'],
$options['phone']['type'],
$options['phone']['options']
)
->add(
$options['mobile']['name'],
$options['mobile']['type'],
$options['mobile']['options']
)
->add(
$options['email']['name'],
$options['email']['type'],
$options['email']['options']
)
->add(
$options['fax']['name'],
$options['fax']['type'],
$options['fax']['options']
)
;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'label' => 'app.ui.contact',
'required' => false,
'phone' => [
'name' => 'phone',
'type' => TelType::class,
'options' => [
'label' => 'sylius.ui.phone_number',
'required' => false,
],
],
'mobile' => [
'name' => 'mobile',
'type' => TelType::class,
'options' => [
'label' => 'app.ui.cell_number',
'required' => false,
],
],
'email' => [
'name' => 'email',
'type' => EmailType::class,
'options' => [
'label' => 'sylius.ui.email',
'required' => false,
],
],
'fax' => [
'name' => 'fax',
'type' => TelType::class,
'options' => [
'label' => 'app.ui.fax',
'required' => false,
],
],
]);
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'app_contact';
}
}
App\Entity\Business:
properties:
# [ other properties that are being correctly validated ]
# I know this example does not make much sense since the properties are
# nullable in the ContactAwareTrait but just for the sake of testing
phone:
- NotBlank:
groups: [admin]
mobile:
- NotBlank:
groups: [admin]
email:
- NotBlank:
groups: [admin]
fax:
- NotBlank:
groups: [admin]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment