2013-04-11 3 views
2

У меня есть набор полей, который используется как в форме «добавить», так и «отредактировать».NoRecordExists inputfilter

Набор для ввода InputFilterProviderInterface для его проверки.

При проверке операции добавления мне нужно проверить запись базы данных с тем же значением, которое еще не существует в базе данных, поэтому я использую валидатор NoRecordExists.

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

Итак, я перехожу к опции exclude валидатора NoRecordExists и исключаю запись с «id» (это мое основное поле ключа) записи, которую я редактирую.

Так что я почти там, единственное, что я не могу решить, - это получить значение «id», которое я хочу исключить, в момент, когда я создаю входной фильтр в getInputFilterSpecification.

Вот мой код на поле. Если кто-нибудь скажет мне, как получить доступ к другим свойствам формы (или связанного объекта) с getInputFilterSpecification, я бы очень сильно хотел.

Возможно, мне нужно реализовать свой imputfilter по-другому, чтобы это сделать? Или даже реализовать пользовательский валидатор? Но, безусловно, пользовательский валидатор был бы излишним для того, что казалось бы довольно обычным случаем использования ...

Большое спасибо заранее. : WQ

<?php 
namespace Kickoff\Form\Competition; 

use Kickoff\Form\AbstractFieldset, 
    Kickoff\Model\Entities\Competition, 
    DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator, 
    Zend\InputFilter\InputFilterProviderInterface; 


class CompetitionFieldset extends AbstractFieldset implements InputFilterProviderInterface 
{ 
    public function init() 
    { 
     $this->setName('Competition') 
      ->setHydrator(new DoctrineHydrator($this->getObjectManager(),'Kickoff\Model\Entities\Competition')) 
      ->setObject(new Competition()) 
      ->setLabel('Competition') 
      ->setAttribute('class','form-collection'); 

     $this->add(array(
      'type' => 'Zend\Form\Element\Hidden', 
      'name' => 'id', 
     )); 

     $this->add(array(
      'name' => 'name', 
      'options' => array(
       'label' => 'Competition name', 
       'admin_inline' => true, 
      ), 
     )); 

     $this->add(array(
      'name' => 'long_name', 
      'options' => array(
       'label' => 'Competition long name', 
       'admin_inline' => true, 
      ), 
      'attributes' => array(
       'class' => 'input-xxlarge', 
      ), 
     )); 

     $this->add(array(
      'type' => 'Zend\Form\Element\Collection', 
      'name' => 'leagues', 
      'options' => array(
       'label' => 'Leagues', 
       'count' => 0, 
       'should_create_template' => true, 
       'allow_add' => true, 
       'target_element' => array(
        'type' => 'LeagueFieldset', 
       ), 
      ), 
     )); 
    } 


    /** 
    * Implement InputFilterProviderInterface 
    */ 
    public function getInputFilterSpecification() 
    { 
     return array(
      'name' => array(
       'filters' => array(
        array('name' => 'Zend\Filter\StringTrim'), 
       ), 
       'validators' => array(
        'notempty' => array(
         'name' => 'NotEmpty', 
         'break_chain_on_failure' => true, 
         'options' => array(
          'messages' => array('isEmpty' => 'Competition name is required.',), 
         ), 
        ), 
        'length' => array(
         'name' => 'StringLength', 
         'options' => array(
          'max' => '64', 
          'messages' => array(
           'stringLengthTooLong' => 'Competition name must be no more than 64 characters.', 
          ), 
         ), 
        ), 
        'unique' => array(
         'name' => 'Db\NoRecordExists', 
         'options' => array(
          'table' => 'competition', 
          'field' => 'name', 
          'adapter' => $this->serviceManager->getServiceLocator()->get('db'), 
          'exclude' => array(
           'field' => 'id', 
           'value' => '', 
          ), 
          'messages' => array(
           'recordFound' => 'A competition already exists with this name', 
          ), 
         ), 
        ), 
       ), 
      ), 
      'long_name' => array(
       'filters' => array(
        array('name' => 'Zend\Filter\StringTrim'), 
       ), 
       'validators' => array(
        'length' => array(
         'name' => 'StringLength', 
         'options' => array(
          'max' => '128', 
          'messages' => array(
           'stringLengthTooLong' => 'Competition long name must be no more than 128 characters.', 
          ), 
         ), 
        ), 
       ), 
      ), 
     ); 
    } 
} 

Edit: добавление моего 'изменить' действие контроллера на этот пост:

public function editCompetitionAction() 
{ 
    $id = $this->params()->fromRoute('competition_id'); 

    $repository = $this->getEntityManager()->getRepository('Kickoff\Model\Entities\Competition'); 
    $competition = $repository->find($id); 

    if (null == $competition) { 
     $this->getResponse()->setStatusCode(404); 
     return; 
    } 

    $formManager = $this->serviceLocator->get('FormElementManager'); 
    $form = $formManager->get('Kickoff\Form\Competition\CompetitionForm'); 
    $form->bind($competition); 

    $request = $this->getRequest(); 
    if ($request->isPost()) { 
     $form->setData($request->getPost()); 
     $this->logger->debug("Validator is ".print_r($form->getValidator(),1)); 
     if ($form->isValid()) { 
      $this->getEntityManager()->persist($competition); 
      $this->getEntityManager()->flush(); 
     } 
    } 

    return array(
     'form' => $form, 
    ); 
} 
+0

Доступ к валидатор от контроллера после того, как форма была отправлена, а затем вы изменить валидатор к вашему желанию;) – Sam

+0

Спасибо Сэму, я посмотрю на это и предложение Эндрю ниже. – familymangreg

ответ

1

Было бы проще, чтобы проверить, что условие вне InputFilter.

Если вы сделаете это, вы можете использовать ту же форму для обновления и вставки.

Вы можете либо) использовать отдельную акцию для обновления и вставки (CRUD) или б), если вы хотите, чтобы обновить/вставить в состоянии сделать что-то вроде этого

// form validates for update or insert now... 

if($form->isValid()) { 
    if($mapper->exists($object)) { 
     $mapper->update($object); 
    } 
    else { 
     $mapper->save($object); 
    } 
} 
+0

Андрей, спасибо за ваш комментарий. Я фактически использую Doctrine для управления моими сущностями, поэтому вставка/обновление CRUD заботится обо мне, просто сохраняя существующий или новый объект. Я посмотрю на проверку дубликата вне проверки формы. Кроме того, я обновлю свое первоначальное сообщение, чтобы включить действие контроллера «edit». – familymangreg

0

Используя этот валидатор в этом случай неправильный.

Что происходит: валидатор отправляет запрос SELECT в базу данных. Если он что-то найдет, он сообщит «недействительно».

Если он не находит что-то, он будет сообщать «действительный», но что, если в то же время второй запрос делает то же самое, а также возвращает «действительный». Кто выигрывает? И как происходит сбой одного обработанного запроса, потому что, очевидно, вы хотите записать ввод в базу данных?

Это проблема TOCTOU. Запись уникальных записей в базу данных должна выполняться только путем вставки новой записи и дождаться, когда база данных будет жаловаться на неисторическое нарушение индекса. Это ожидаемый результат операции записи и может быть обработан.

Валидатор не бесполезен: вы все равно можете использовать его, чтобы проверить, есть ли что-то в пути в базе данных, например.в запросе Ajax, когда пользователь находится в процессе заполнения своего имени пользователя и т. д. Проверка и получение логического значения из базы данных только для чтения полностью в порядке. Но в качестве валидатора ввода это неверно.

0

Это мой рабочий раствор:

$inputFilter->add($factory->createInput(array(
      'name'  => 'role_name', 
      'required' => true, 
      'filters' => array(
       array('name' => 'StripTags') 
      ), 
      'validators' => array(
       array(
        'name' => 'StringLength', 
        'options' => array(
         'encoding' => 'UTF-8', 
         'min'  => 2, 
         'max'  => 15 
        ), 
       ), 
       array(
        'name' => 'Zend\Validator\Db\NoRecordExists', 
        'options' => array(
         'table' => 'user_role', 
         'field' => 'code', 
         'adapter' => \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::getStaticAdapter(), 
         'messages' => array(
          \Zend\Validator\Db\NoRecordExists::ERROR_RECORD_FOUND => 'The specified name already exists in database' 
         ), 
        ), 
       ), 
      ), 
     ))); 
0

Я нашел решение этой проблемы. В принципе, валидатор NoRecordExists по умолчанию ожидает, что значение вместе с столбцом будет исключено в параметрах конфигурации. Это может быть изменено в контроллере, как указано Ritesh; Я немного поиграл и получил это решение.

Я использую переменную контекстного массива, которая доступна в функции isValid. Вместо того, чтобы послать значение идентификатора, вы отправляете в значении поля формы, чтобы забрать из

в InputFilter вы следующие

$this->add (array (
    'name' => 'user_email', 
    'required' => true, 
    'filters' => array (
     array ( 
      'name' => 'StringTrim', 
     ), 
     array ( 
      'name' => 'StripTags', 
     ), 
    ), 
    'validators' => array (
     array (
      'name' => 'EmailAddress', 
      'options' => array (
       'domain' => true, 
      ) 
     ), 
     array (
      'name' => 'Application\Validator\NoRecordExists', 
      'options' => array (
       'table' => 'user', 
       'field' => 'user_email', 
       'adapter' => \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::getStaticAdapter(), 
       'exclude' => array(
        'field' => 'user_id', 
        'formvalue' => 'user_id', 
       ), 
      ) 
     ), 

    ) 
)); 

Существует скрытая элемент User_ID определяется в виде; значение, установленным там используется внутри проверки

<?php 

namespace Application\Validator; 

class NoRecordExists extends \Zend\Validator\Db\NoRecordExists { 

    public function isValid($value, $context=array()) { 

     $exclude = $this->getExclude(); 

     if(is_array($exclude)){ 
      if (array_key_exists('formvalue', $exclude)) { 
       $formvalue = $exclude[ 'formvalue' ]; 
       $exclude[ 'value' ] = $context[ $formvalue ]; 
       $this->setExclude($exclude); 
      } 
     } 

     return parent::isValid($value); 

    } 

} 

Надеется, что это помогает

0

Здесь я нашел решения для обоего Добавить Действие и Edit Action

Контроллер:

В addAction:

  $postData = $this->request->getPost(); 
      $dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter'); 
      $form->setInputFilter(new FormFilter($dbAdapter)); 
      $form->setData ($postData); 
      if (!$form->isValid()) { 
       $viewModel->error = true; 
       return $viewModel; 
      } 

В editAction:

  $post = $request->getPost(); 
      $dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');     
      $form->setInputFilter(new FormFilter($dbAdapter,$Id)); 
      $form->setData ($post); 
      $Id = $post['id']; 
      if (!$form->isValid()) { 
        $viewModel->error = true; 
        $viewModel->Id = $Id; 
        $viewModel->form = $form; 
        return $viewModel; 
      } 

В Форма фильтра файл:

class FormFilter extends InputFilter { 

    public function __construct ($dbAdapter, $id = '') 
    { 
     $this->dbAdapter = $dbAdapter; 
     $this->add(array(
       'name'  => 'name', 
       'required' => true, 
       'filters' => array(
         array('name' => 'StripTags'), 
         array('name' => 'StringTrim'), 
       ), 
       'validators' => array(
         array(
           'name' => 'StringLength', 
           'options' => array(
             'encoding' => 'UTF-8' 
           ), 
         ), 
         array(
           'name' => 'Zend\Validator\Db\NoRecordExists', 
           'options' => array(
             'table' => 'test', 
             'field' => 'name', 
             'adapter' => $this->dbAdapter, 
             'exclude' => array(
               'field' => 'id', 
               'value' => $id, 
             ), 
             'messages' => array(
               \Zend\Validator\Db\NoRecordExists::ERROR_RECORD_FOUND => 'The specified name already exists in database' 
             ), 
           ), 
         ), 
       ), 
     )); 
    } 
} 
Смежные вопросы