2013-04-11 52 views
2

我有一個在'添加'和'編輯'表單中使用的字段集。NoRecordExists inputfilter

字段集實現InputFilterProviderInterface提供了驗證。

當驗證添加操作時,我需要檢查數據庫中不存在的數據庫記錄,因此我使用NoRecordExists驗證程序。

目前爲止都很好。但是,當我在編輯表單中使用相同的字段集時,驗證將失敗,因爲顯然已經有具有特定值的記錄,其正在編輯的記錄。

因此,我轉向NoRecordExists驗證程序的exclude選項,並使用正在編輯的記錄的'id'(這是我的主鍵字段)排除該記錄。

所以我快到了,唯一不能解決的問題是如何在我創建輸入過濾器的時候得到'id'值,我想在getInputFilterSpecification中創建inputfilter。

這是我的fieldset代碼。如果有人能告訴我如何從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.', 
          ), 
         ), 
        ), 
       ), 
      ), 
     ); 
    } 
} 

編輯:加入我的「編輯」控制器動作這個帖子:

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 2013-04-11 18:35:28

+0

謝謝山姆,我會看看這個和安德魯的建議下面。 – familymangreg 2013-04-12 07:48:37

回答

1

這將是簡單的檢查輸入過濾以外這一條件。

如果你這樣做,那麼你可以使用相同的形式都更新和插入。

你既可以a)使用一個單獨的行動,以更新和插入(CRUD)或b)如果你希望他們更新/插入一個條件做這樣的事情

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

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

安德魯,感謝您的評論。我實際上是在使用Doctrine來管理我的實體,因此只需堅持現有的或新的實體,就可以爲我提供CRUD插入/更新。我會看看驗證表單驗證以外的重複內容。此外,我會更新我的原始帖子,以包含我的'編輯'控制器操作。 – familymangreg 2013-04-12 07:45:03

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函數中可用的上下文數組變量。而不是發送的id值,你在表單字段的值發送給在輸入過濾從

拿起你有以下

$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

在這裏,我找到了兩個解決方案添加操作編輯動作

控制器:

In 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' 
             ), 
           ), 
         ), 
       ), 
     )); 
    } 
} 
相關問題