Symfony Пустое поле формы принимает значение NULL

A1x

Новичок
Разбираюсь с SF2, создал таблицу, сгенерировал сущность, создал форму
в таблице есть два текстовых поля, одно из них обязательное, другое может быть пустой строкой
при сабмите формы если оставляю поле street2 пустым получаю на нем ошибку - This value should not be null.

Что я делаю не так?

таблица
Код:
`street` varchar(255) NOT NULL DEFAULT '',
`street2` varchar(255) NOT NULL DEFAULT '',
класс сущности
PHP:
/**
* Customer
*
* @ORM\Entity
* @ORM\Table(name="customer", indexes={@ORM\Index(name="customer_country_ix", columns={"country"})})
* @ORM\HasLifecycleCallbacks
*/
class Customer
{
    /**
    * @var string
    *
    * @Assert\NotBlank()
    * @ORM\Column(name="street", type="string", length=255, nullable=false)
    */
    private $street = '';

    /**
    * @var string
    *
    * @Assert\NotNull()
    * @ORM\Column(name="street2", type="string", length=255, nullable=false, options={"default":""})
    */
    private $street2 = '';

    // ....

    /**
    * Set street
    *
    * @param string $street
    * @return Customer
    */
    public function setStreet($street)
    {

        $this->street = $street;

        return $this;
    }

   
    /**
    * Set street2
    *
    * @param string $street2
    * @return Customer
    */
    public function setStreet2($street2)
    {
//        if (NULL === $street2) {
//            $street2 = '';
//        }
        $this->street2 = $street2;

        return $this;
    }


}
форма
PHP:
class CustomerType extends AbstractType
{
    /**
    * @param FormBuilderInterface $builder
    * @param array $options
    */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            // ...
            ->add('street', 'text', ['label' => 'Street address'])
            ->add('street2', 'text', ['label' => 'Street address 2', 'required' => FALSE, 'empty_data' => ''])
            // ...
        ;
    }

    // .....
}
 

keltanas

marty cats
Что я делаю не так?
Код:
@Assert\NotNull()
Именно это аннотация для валидатора, после проверки которым, похоже, и выводится ошибка.
Код:
@ORM\Column(name="street2", type="string", length=255, nullable=false, options={"default":""})
Это начинает работать, когда сохраняешь сущность.
 

A1x

Новичок
keltanas сасибо за ответ, но это сути не меняет, если я уберу @Assert\NotNull() то будет ошибка SQL - попытка вставить NULL в поле с NOT NULL
я передаю в форме пустую строку и хочу получить пустую строку, а вместо этого получаю NULL

это тем более странно, учитывая что в доке написано что там должна быть пустая строка по умолчанию - http://symfony.com/doc/current/reference/forms/types/text.html#empty-data
empty_data
type: mixed

The default value is '' (the empty string).

This option determines what value the field will return when the submitted value is empty.

But you can customize this to your needs. For example, if you want the gender choice field to be explicitly set to null when no value is selected, you can do it like this:
 

A1x

Новичок
вот тикет об этом на гитхабе - https://github.com/symfony/symfony/issues/5906
висит уже больше двух лет, тем временем документация не соответствует действительности

остается решение или делать рпроверку в сеттере if (NULL === $street2) $street2 = ''; как я подумал с самого начала
или DataTransfromer как описано тут - http://stackoverflow.com/questions/24792285/symfony-form-field-attribute-empty-data-ignored

вообще странная какая-то ситуация. Что больше никто с этим не сталкивался?
 
Последнее редактирование:

keltanas

marty cats
A1x можешь уточнить, какая версия Symfony, и каким образом связываются Request и сущность в контроллере?
 

A1x

Новичок
Symfony 2.6.6

контроллер выглядит так
PHP:
namespace Crm\CrmBundle\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Crm\CrmBundle\Entity\Customer;
use Crm\CrmBundle\Form\CustomerType;

/**
* @Route("/customers")
*/
class CustomerController extends Controller
{

    /**
    * @Route("/new", name="customers_new")
    * @Template()
    */
    public function newAction(Request $request)
    {
        $entity = new Customer();
        $form = $this->createForm(new CustomerType(), $entity,
                [
            'action' => $this->generateUrl('customers_new'),
            'method' => 'POST',
        ]);

        $form->add('submit', 'submit', array('label' => 'Create'));

        $form->handleRequest($request);

        if ($form->isValid()) {
            // .....    
        }

        return [
            'entity' => $entity,
            'form' => $form->createView(),
        ];
    }

    // .....

}
 

keltanas

marty cats
Понятно. Посмотрел, почему у меня не возникает такой ошибки. Просто позволяю доктрине записывать null в качестве пустого значения =) В общем-то ничего плохого в этом нет.
 

A1x

Новичок
А я всегда делаю поля с NOT NULL если специально не собираюсь использовать NULL. Вот только начал изучать Симфони, самый крутой фреймворк, а тут сразу такое. Напьюсь сегодня.
 

WMix

герр M:)ller
Партнер клуба
А я всегда делаю поля с NOT NULL
я наоборот, пусто это уже значение - значит его уже установили, а наль это неизвестность.
если специально не собираюсь использовать NULL.
если только без этого значения можно жить.
 

A1x

Новичок
WMix в данном случае можно сказать что поле street2 всегда известно - если запись была создана значит она прошла валидацию, валидация позволяет оставить поле street2 пустым, если его оставили пустым значит известно что оно пустое. То есть вполне логично сделать это поле NOT NULL
 

A1x

Новичок
Пришел к такому более удобному решению: регистрируем расширение типа для полей формы
которое добавляет новую опцию null_value
PHP:
<?php

namespace Nk\CrmBundle\Form\Extension;

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Nk\CrmBundle\Form\DataTransformer\NullValueTransformer;

class NullValueTypeExtension extends AbstractTypeExtension
{

    public function getExtendedType()
    {
        return 'form';
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if (isset($options['null_value'])) {
            $builder->addViewTransformer(new NullValueTransformer($options['null_value']));
        }
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(['null_value' => NULL]);
    }

}
PHP:
<?php

namespace Nk\CrmBundle\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;

class NullValueTransformer implements DataTransformerInterface
{

    protected $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    /**
    * Normalized ---> view
    *
    * @param  string|null $value
    * @return string
    */
    public function transform($value)
    {
        if ($this->value == $value) {
            return NULL;
        }

        return $value;
    }

    /**
    * View ---> normalized
    *
    * @param  string $value
    * @return mixed
    */
    public function reverseTransform($value)
    {
        if (NULL === $value) {
            return $this->value;
        }

        return $value;
    }

}
теперь при добавлении поля можно установить эту опцию при необходимости
PHP:
$form = $this->createFormBuilder()
                ->add('name', 'text', ['required' => FALSE, 'null_value' => ''])
                ->add('email', 'email', ['required' => FALSE])
                ->add('birthday', 'date', ['empty_value' => '--', 'required' => FALSE])
                ->add('message', 'textarea', ['required' => FALSE])
                ->add('level', 'number', ['required' => FALSE, 'null_value' => 0])
                ->add('send', 'submit')
                ->getForm();
 

WMix

герр M:)ller
Партнер клуба
PHP:
$values=$form->getValues();
$model->insert(array(
  'level' => empty($values['level']) ? null: $values['level']
))
 

WMix

герр M:)ller
Партнер клуба
это так абстрактно.. смысл что модель решает как записывать а форма только принимает валидирует и фильтрует
 

A1x

Новичок
ну валидация может быть и в модели (Entity) - /** @Assert\NotNull() */
хочется как-то больше использовать возможности архитектуры, а не костыли
 

Вурдалак

Продвинутый новичок
ну валидация может быть и в модели (Entity) - /** @Assert\NotNull() */
хочется как-то больше использовать возможности архитектуры, а не костыли
Это не валидация в модели, валидация у тебя в валидаторе. У тебя типичная анемичная модель.

больше использовать возможности архитектуры, а не костыли
Следует читать как: «хочется посильнее завязаться на Symfony».
 
  • Like
Реакции: A1x

WMix

герр M:)ller
Партнер клуба
форма и NULL очень разные понятия, а внутри имплементация или в "transformer" мне не интересно
default чтоль назови
 
Последнее редактирование:

A1x

Новичок
форма и NULL очень разные понятия,
я вроде не говорил обратного

а внутри имплементация или в "transformer" мне не интересно
внутри чего?

default чтоль назови
можно и default, но не уверен что эта опция уже не используется. Есть опция empty_data http://symfony.com/doc/current/reference/forms/types/text.html#empty-data
но она почему-то не работает как ожидается
 
Сверху