@v7sila

Валидация части объекта Symfony?

Есть сущьность User. У данной сущьности методы которые валидируются анотациями.
Сущьность
/**
 * @ORM\Table(name="app_users")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
 * @UniqueEntity(
 * 		"username",
 * 		message="Логин уже используется"
 * )
 * @UniqueEntity(
 * 		"email",
 * 		message="Email уже используется"
 * )
 */
class User implements AdvancedUserInterface, \Serializable
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=25, unique=true)
	 * @Assert\NotBlank(
	 *     message="Логин не должен быть пустым"
	 * )
	 * @Assert\Length(
	 *      min = 3,
	 *      max = 50,
	 *      minMessage = "Логин должен содержать не меньше {{ limit }} символов",
	 *      maxMessage = "Логин должен содержать не меньше {{ limit }} символов"
	 * )
	 * @Assert\Regex(
	 * 		pattern="/^[A-Za-z0-9_-]+$/",
	 *     	message="Логин может состоять только из латинских из букв, цифр, дефисов и подчёркиваний. Длина от 3 до 16 символов."
	 * )
     */
    private $username;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $plainPassword;

    /**
     * @ORM\Column(type="string", length=64)
	 * @Assert\Length(
	 *      min = 6,
	 *      max = 64,
	 *      minMessage = "Пароль должен содержать не меньше {{ limit }} символов",
	 *      maxMessage = "Пароль должен содержать не меньше {{ limit }} символов"
	 * )
	 * * @Assert\NotBlank(
	 *     message="Пароль не должен быть пустым"
	 * )
     */
    private $password;

    /**
     * @ORM\Column(type="string", length=60, unique=true)
     * @Assert\NotBlank(
     *     message="Email не должен быть пустым"
     * )
     * @Assert\Length(
     *      min = 6,
     *      max = 50,
     *      minMessage = "Email должен содержать не меньше {{ limit }} символов",
     *      maxMessage = "Email должен содержать не меньше {{ limit }} символов"
     * )
     * @Assert\Email(
     *     message = "Email {{ value }} имеет не верный формат.",
     *     checkMX = true
     * )
     */
    private $email;


В форме использутся только $password.
$builder
			->add('password', RepeatedType::class, array(
				'type' => PasswordType::class,
				'invalid_message' => 'Поля паролей должны совпадать.',
				'options' => array('attr' => array('class' => 'password-field')),
				'required' => true,
				'first_options'  => array('label' => 'Новый пароль'),
				'second_options' => array('label' => 'Повторение нового пароля'),
			))
			->add('save', SubmitType::class)
			->add( 'new_password_hidden' ,  HiddenType :: class, [
				'mapped' => false,
			])
		;


// Класс сущности
$user = new \AppBundle\Entity\User();
// Построение формы
$form = $this->createForm(NewPassword::class, $user);

Валидатор возвращает false так как в объекте валиден только пароль.
var_dump($form->isValid());
Результат bool(false);

!!!Как использовать класс User в форме, что бы $form->isValid() вернул true?
  • Вопрос задан
  • 162 просмотра
Решения вопроса 2
artemylapko
@artemylapko
Symfony, Doctrine developer. Немного js и python.
Не пихай в форму сущность. Гугли про dto. И не надо валидировать сущность. Нужно валидировать запрос! Остальным база займется...
Ответ написан
prototype_denis
@prototype_denis
Symfony
Вам необходимо использовать группы валидации.

symfony.com/doc/current/form/validation_groups.html

Под капотом ваша сущность попадает на эту строку где валидируется весь объект.

В форму попадают все ошибки и только ошибка пароля (если она есть) попадёт в FormError конкретного поля. Остальные попадут в рутовую форму.

Соответственно, если малой кровью - добавьте две группы для пароля:

symfony.com/doc/current/validation/groups.html - одну по умолчанию, для обратной совместимости, если данная сущность уже где-то валидируется и не нужгно ломать обратную совместимость и вторую, специфичную для формы. И при создании формы, или же в опциях сборщика укажите данную группу (ключ validation_groups)

Решение данной проблемы - 3 строчки кода. (2 на Assert и одну к опциям формы)

@Assert\NotBlank(message="Пароль не должен быть пустым", groups={...})
@Assert\Length(..., groups={...})


$resolver->setDefaults([
    'validation_groups' => [...]
]);
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@v7sila Автор вопроса
Действительно. Не стоит использовать сущность для валидации. Сущность должна быть всегда валидной.

Использовал отдельный класс для валидации пароля.
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;

class Password
{
    /**
	 *
	 * @Assert\Length(
	 *      min = 6,
	 *      max = 64,
	 *      minMessage = "Пароль должен содержать не меньше {{ limit }} символов",
	 *      maxMessage = "Пароль должен содержать не меньше {{ limit }} символов"
	 * )
	 * * @Assert\NotBlank(
	 *     message="Пароль не должен быть пустым"
	 * )
     * @var string
     */
    private $password;


    /**
     * Set password
     *
     * @param string $password
     *
     * @return Password
     */
    public function setPassword($password)
    {
        $this->password = $password;

        return $this;
    }

    /**
     * Get password
     *
     * @return string
     */
    public function getPassword()
    {
        return $this->password;
    }
}

В контроллере
public function newPasswordAction(Request $request){
		$password = new Password();
		$form = $this->createForm(NewPassword::class, $password);
		/........./
	}


Класс формы
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;

class NewPassword extends AbstractType
{
	public function buildForm(FormBuilderInterface $builder, array $options)
	{
		$builder
			->add('password', RepeatedType::class, array(
				'type' => PasswordType::class,
				'invalid_message' => 'Поля паролей должны совпадать.',
				'options' => array('attr' => array('class' => 'password-field')),
				'required' => true,
				'first_options'  => array('label' => 'Новый пароль'),
				'second_options' => array('label' => 'Повторение нового пароля'),
			))
			->add('save', SubmitType::class)
			->add( 'new_password_hidden' ,  HiddenType :: class, [
				'mapped' => false,
			])
		;
	}
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы