ZF2

2012-09-09 12 views
11

संपादित करें में फ़ॉर्म इनपुट/तत्व कैसे बनाएं: मेरा मुख्य प्रश्न अब बन गया है 'मैं अपने फॉर्म, तत्व और इनपुट कक्षाओं के हाथों में कुछ स्वच्छ तरीके से सिद्धांत प्रबंधक प्रबंधक के साथ सेवा प्रबंधक कैसे प्राप्त करूं?' पूर्ण पोस्ट देखने के लिए पढ़ें।ZF2

मैं यहां उदाहरण के लिए कोशिश करने और पूछने जा रहा हूं इसलिए मेरे साथ भालू। मुझे बताएं कि मैं गलत/सही कहां जा रहा हूं या जहां मैं

सुधार कर रहा हूं, मैं पंजीकरण फॉर्म बनाने की कोशिश कर रहा हूं। मैं ZfcUser मॉड्यूल का उपयोग कर सकता हूं लेकिन मैं इसे अपने आप करना चाहता हूं। मैं ZF2 का उपयोग Doctrine2 के साथ भी कर रहा हूं ताकि मुझे उस मॉड्यूल से थोड़ा दूर ले जाया जा सके।

मेरे रणनीति थी यह,

  1. बुलाया पंजीकरण फार्म

  2. प्रत्येक तत्व के लिए अलग 'तत्व' कक्षाएं बनाएं एक रूप कक्षा बनाएं प्रत्येक तत्व का एक इनपुट विनिर्देश

  3. होगा चूंकि प्रत्येक तत्व फॉर्म से एक अलग वर्ग है, इसलिए मैं इकाई को अलग से परीक्षण कर सकता हूं।

सभी ठीक लग रहा था जब तक मैं अपना उपयोगकर्ता नाम तत्व यह है कि जाँच करेगा कि उपयोगकर्ता नाम नहीं है अभी तक उपयोग करने के लिए एक सत्यापनकर्ता जोड़ना चाहते थे।

यहाँ कोड अब तक

namepsace My\Form; 

use Zend\Form\Form, 
    Zend\Form\Element, 
    Zend\InputFilter\Input, 
    Zend\InputFilter\InputFilter, 

/** 
* Class name : Registration 
*/ 
class Registration 
    extends Form 
{ 

    const USERNAME  = 'username'; 
    const EMAIL  = 'email'; 
    const PASSWORD  = 'password'; 
    const PASS_CONFIRM = 'passwordConfirm'; 
    const GENDER  = 'gender'; 
    const CAPTCHA  = 'captcha'; 
    const CSRF   = 'csrf'; 
    const SUBMIT  = 'submit'; 

    private $captcha = 'dumb'; 

    public function prepareForm() 
    { 
     $this->setName('registration'); 

     $this->setAttributes(array(
      'method' => 'post' 
     )); 

     $this->add(array(
      'name'  => self::USERNAME, 
      'type'  => '\My\Form\Element\UsernameElement', 
      'attributes' => array(
       'label'  => 'Username', 
       'autofocus' => 'autofocus' 
      ) 
      ) 
     ); 

     $this->add(array(
      'name'  => self::SUBMIT, 
      'type'  => '\Zend\Form\Element\Submit', 
      'attributes' => array(
       'value' => 'Submit' 
      ) 
     )); 

    } 

} 

मैं एक बहुत मुझे लगता है कि जरूरी नहीं है हटा दिया है। नीचे मेरा उपयोगकर्ता नाम तत्व है।

namespace My\Form\Registration; 

use My\Validator\UsernameNotInUse; 
use Zend\Form\Element\Text, 
    Zend\InputFilter\InputProviderInterface, 
    Zend\Validator\StringLength, 
    Zend\Validator\NotEmpty, 
    Zend\I18n\Validator\Alnum; 

/** 
* 
*/ 
class UsernameElement 
    extends Text 
    implements InputProviderInterface 
{ 

    private $minLength = 3; 
    private $maxLength = 128; 

    public function getInputSpecification() 
    { 
     return array(
      'name'  => $this->getName(), 
      'required' => true, 
      'filters' => array(
       array('name'  => 'StringTrim') 
      ), 
      'validators' => 
      array(
       new NotEmpty(
        array('mesages' => 
         array(
          NotEmpty::IS_EMPTY => 'The username you provided is blank.' 
         ) 
        ) 
       ), 
       new AlNum(array(
        'messages' => array(Alnum::STRING_EMPTY => 'The username can only contain letters and numbers.') 
        ) 
       ), 
       new StringLength(
        array(
         'min'  => $this->getMinLength(), 
         'max'  => $this->getMaxLength(), 
         'messages' => 
         array(
          StringLength::TOO_LONG => 'The username is too long. It cannot be longer than ' . $this->getMaxLength() . ' characters.', 
          StringLength::TOO_SHORT => 'The username is too short. It cannot be shorter than ' . $this->getMinLength() . ' characters.', 
          StringLength::INVALID => 'The username is not valid.. It has to be between ' . $this->getMinLength() . ' and ' . $this->getMaxLength() . ' characters long.', 
         ) 
        ) 
       ), 
       array(
        'name' => '\My\Validator\UsernameNotInUse', 
        'options' => array(
         'messages' => array(
          UsernameNotInUse::ERROR_USERNAME_IN_USE => 'The usarname %value% is already being used by another user.' 
         ) 
        ) 
       ) 
      ) 
     ); 
    }  
} 

अब यहाँ मेरी सत्यापनकर्ता

namespace My\Validator; 

use My\Entity\Helper\User as UserHelper, 
    My\EntityRepository\User as UserRepository; 
use Zend\Validator\AbstractValidator, 
    Zend\ServiceManager\ServiceManagerAwareInterface, 
    Zend\ServiceManager\ServiceLocatorAwareInterface, 
    Zend\ServiceManager\ServiceManager; 

/** 
* 
*/ 
class UsernameNotInUse 
    extends AbstractValidator 
    implements ServiceManagerAwareInterface 
{ 

    const ERROR_USERNAME_IN_USE = 'usernameUsed'; 

    private $serviceManager; 

    /** 
    * 
    * @var UserHelper 
    */ 
    private $userHelper; 
    protected $messageTemplates = array(
     UsernameNotInUse::ERROR_USERNAME_IN_USE => 'The username you specified is being used already.' 
    ); 

    public function isValid($value) 
    { 
     $inUse = $this->getUserHelper()->isUsernameInUse($value); 
     if($inUse) 
     { 
      $this->error(UsernameNotInUse::ERROR_USERNAME_IN_USE, $value); 
     } 

     return !$inUse; 
    } 

    public function setUserHelper(UserHelper $mapper) 
    { 
     $this->userHelper = $mapper; 
     return $this; 
    } 

    /** 
    * @return My\EntityRepository\User 
    */ 
    public function getUserHelper() 
    { 
     if($this->userHelper == null) 
     { 
      $this->setUserHelper($this->getServiceManager()->get('doctrine.entitymanager.orm_default')->getObjectRepository('My\Entity\User')); 
     } 
     return $this->userHelper; 
    } 

    public function setServiceManager(ServiceManager $serviceManager) 
    { 
     echo get_class($serviceManager); 
     echo var_dump($serviceManager); 
     $this->serviceManager = $serviceManager; 
     return $this; 
    } 

    /** 
    * 
    * @return ServiceManager 
    */ 
    public function getServiceManager() 
    { 
     return $this->serviceManager; 
    } 

} 

क्यों यह मेरे लिए एक अच्छा विचार की तरह लग किया है?

  1. यह एक अच्छी टेस्टेबिलिटी/पुन: उपयोग करने की पसंद की तरह लग रहा था क्योंकि मैं आवश्यकता होने पर अपने आवेदन में अलग-अलग तत्वों का दोबारा उपयोग कर सकता हूं।

  2. मैं प्रत्येक तत्व द्वारा उत्पन्न प्रत्येक इनपुट का परीक्षण कर सकता हूं यह सुनिश्चित करने के लिए कि यह इनपुट को सही ढंग से स्वीकार/अस्वीकार करता है।

यह तत्व

public function testFactoryCreation() 
{ 
    $fac = new Factory(); 

    $element = $fac->createElement(array(
     'type' => '\My\Form\Registration\UsernameElement' 
     )); 
    /* @var $element \My\Form\Registration\UsernameElement */ 

    $this->assertInstanceOf('\My\Form\Registration\UsernameElement', 
          $element); 

    $input  = $fac->getInputFilterFactory()->createInput($element->getInputSpecification()); 
    $validators = $input->getValidatorChain()->getValidators(); 
    /* @var $validators \Zend\Validator\ValidatorChain */ 

    $expectedValidators = array(
     'Zend\Validator\StringLength', 
     'Zend\Validator\NotEmpty', 
     'Zend\I18n\Validator\Alnum', 
     'My\Validator\UsernameNotInUse' 
    ); 

    foreach($validators as $validator) 
    { 
     $actualClass = get_class($validator['instance']); 
     $this->assertContains($actualClass, $expectedValidators); 

     switch($actualClass) 
     { 
      case 'My\Validator\UsernameNotInUse': 
       $helper = $validator['instance']->getUserHelper(); 
       //HAVING A PROBLEM HERE 
       $this->assertNotNull($helper); 
       break; 

      default: 

       break; 
     } 
    } 

} 
के लिए मेरे इकाई परीक्षण का उदाहरण है

समस्या मैं आ रही है कि सत्यापनकर्ता केँ ठीक से नहीं लाई जा सकती है, जो वास्तव में सिद्धांत से एक UserRepository है । ऐसा इसलिए हो रहा है क्योंकि वैधकर्ता केवल अनुप्रयोग प्रबंधक के उपयोग के बजाय ValidatorPluginManager को ServiceManager के रूप में एक्सेस प्राप्त करते हैं।

मुझे यह त्रुटि वैलिडेटर भाग के लिए मिलती है, हालांकि अगर मैं सामान्य सेवा प्रबंधक पर एक ही विधि प्राप्त करता हूं तो यह कोई समस्या नहीं है।

1) Test\My\Form\Registration\UsernameElementTest::testFactoryCreation 
Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for doctrine.entitymanager.orm_default 

var_dump ($ serviceManager) सत्यापनकर्ता में मुझे पता चलता है कि यह वर्ग ValidatorPluginManager की है।

मैं इतना

'service_manager' => array(
       'factories' => array(
        'My\Validator\UsernameNotInUse' => function($sm) 
        { 
         $validator = new \My\Validator\UsernameNotInUse(); 
         $em  = $serviceManager->get('doctrine.entitymanager.orm_default'); 
         /* @var $em \Doctrine\ORM\EntityManager */ 
         $validator->setUserHelper($em->getRepository('\My\Entity\User')); 

         return $validator; 
        } 
       ) 

तरह service_manager प्रविष्टि में एक कारखाना लगाने की कोशिश की लेकिन क्योंकि यह अनुप्रयोग स्तर सेवा प्रबंधक से सलाह नहीं कर रहा है काम नहीं किया।

तो, समग्र, यहाँ मेरे सवालों हैं:

  1. फार्म और तत्वों एक अच्छा एक को अलग करने की इस रणनीति है? क्या मुझे इस तरह से चलना चाहिए? विकल्प क्या हैं? (मैं टेस्टेबिलिटी के लिए सामान तोड़ने के लिए हूं) मैं केवल मूल रूप से सभी इनपुट के संयोजन के साथ ही फॉर्म का परीक्षण करने जा रहा था, लेकिन ऐसा लगता था कि मैं बहुत अधिक करने की कोशिश कर रहा हूं।

  2. मैं ऊपर दिए गए मुद्दे को कैसे हल करूं?

  3. क्या मुझे ज़ेंड के फॉर्म/एलिमेंट/इनपुट पार्ट्स का उपयोग किसी अन्य तरीके से करना चाहिए जिसे मैं नहीं देख रहा हूं?

+0

editin आप पहले से ही है फ़ॉर्म के बारे में [docs] (http://zf2.readthedocs.org/en/latest/modules/zend.form.quick-start.html) की जांच की? मैं विशेष रूप से एनोटेशन का उपयोग करने की सलाह देता हूं, क्योंकि यह फॉर्म बनाने के लिए सबसे तेज़ तरीका है। –

+0

@DanielM मैंने आपके द्वारा उल्लेखित दस्तावेज़ों पर ध्यान दिया है, लेकिन 'मैं प्रत्येक इनपुट को अलग-अलग परीक्षण कैसे कर सकता हूं?' का सवाल बाकी है। एनोटेशन विधि के साथ मुझे पूरी तरह से एहसास हुआ फॉर्म सही मिलेगा? तो क्या मुझे हर इनपुट संयोजन का उपयोग करने के लिए मजबूर नहीं किया जाएगा? –

+0

ठीक है, मैं उनका परीक्षण नहीं करता हूं। मुझे नहीं लगता कि परीक्षण की आवश्यकता यहां है क्योंकि तत्व वर्गों का परीक्षण किया जाता है, वैधकर्ताओं का परीक्षण किया जाता है और इनपुट फ़िल्टर भी होते हैं। बेशक, यदि आप किसी विशेष उद्देश्य के लिए एक नई एलिमेंट क्लास बनाते हैं जो मौजूदा तत्वों के अनुरूप नहीं है, तो आपको नए टेस्ट केस बनाना चाहिए। अन्यथा, ठीक है। और हां, एनोटेशन का उपयोग करके बनाए गए फॉर्मों को बिना किसी काम के पूरी तरह से प्रस्तुत किया जा सकता है, 'यह $ echo-> formCollection ($ myForm) को छोड़कर;' दृश्य के अंदर यदि आपको किसी भी अनुकूलित प्रतिपादन की आवश्यकता नहीं है। –

उत्तर

8

यह मेरा वैधकर्ता है, इकाई प्रबंधक को इंजेक्ट करने और किसी भी सिद्धांत इकाई के साथ काम करने के लिए एक स्थिर विधि का उपयोग करके।

<?php 

namespace Base\Validator; 

use Traversable; 
use Zend\Stdlib\ArrayUtils; 
use Zend\Validator\AbstractValidator; 
use Doctrine\ORM\EntityManager; 

class EntityUnique extends AbstractValidator 
{ 
    const EXISTS = 'exists'; 

    protected $messageTemplates = array(
     self::EXISTS => "A %entity% record already exists with %attribute% %value%", 
    ); 

    protected $messageVariables = array(
     'entity' => '_entity', 
     'attribute' => '_attribute', 
    ); 


    protected $_entity; 
    protected $_attribute; 
    protected $_exclude; 

    protected static $_entityManager; 

    public static function setEntityManager(EntityManager $em) { 

     self::$_entityManager = $em; 
    } 

    public function getEntityManager() { 

     if (!self::$_entityManager) { 

      throw new \Exception('No entitymanager present'); 
     } 

     return self::$_entityManager; 
    } 

    public function __construct($options = null) 
    { 
     if ($options instanceof Traversable) { 
      $options = ArrayUtils::iteratorToArray($token); 
     } 

     if (is_array($options)) { 

      if (array_key_exists('entity', $options)) { 

       $this->_entity = $options['entity']; 
      } 

      if (array_key_exists('attribute', $options)) { 

       $this->_attribute = $options['attribute']; 
      } 

      if (array_key_exists('exclude', $options)) { 

       if (!is_array($options['exclude']) || 
        !array_key_exists('attribute', $options['exclude']) || 
        !array_key_exists('value', $options['exclude'])) { 

        throw new \Exception('exclude option must contain attribute and value keys'); 
       } 

       $this->_exclude = $options['exclude']; 
      } 
     } 

     parent::__construct(is_array($options) ? $options : null); 
    } 

    public function isValid($value, $context = null) 
    { 
     $this->setValue($value); 

     $queryBuilder = $this->getEntityManager() 
      ->createQueryBuilder() 
      ->from($this->_entity, 'e') 
      ->select('COUNT(e)') 
      ->where('e.'. $this->_attribute . ' = :value') 
      ->setParameter('value', $this->getValue()); 

     if ($this->_exclude) { 

      $queryBuilder = $queryBuilder->andWhere('e.'. $this->_exclude['attribute'] . ' != :exclude') 
       ->setParameter('exclude', $this->_exclude['value']); 
     } 

     $query = $queryBuilder->getQuery();   
     if ((integer)$query->getSingleScalarResult() !== 0) { 

      $this->error(self::EXISTS); 
      return false; 
     } 

     return true; 
    } 
} 

यानी। मैं इन प्रपत्र तत्व है जो भी जांच की जाती है और ठीक काम करने के लिए यह उपयोग कर रहा हूँ:

<?php 

namespace User\Form\Element; 

use Zend\Form\Element\Text; 
use Zend\InputFilter\InputProviderInterface; 

class Username extends Text implements InputProviderInterface 
{ 
    public function __construct() { 

     parent::__construct('username'); 
     $this->setLabel('Benutzername'); 
     $this->setAttribute('id', 'username'); 
    } 

    public function getInputSpecification() { 

     return array(
      'name' => $this->getName(), 
      'required' => true, 
      'filters' => array(
       array(
        'name' => 'StringTrim' 
       ), 
      ), 
      'validators' => array(
       array(
        'name' => 'NotEmpty', 
        'break_chain_on_failure' => true, 
        'options' => array(
         'messages' => array(
          'isEmpty' => 'Bitte geben Sie einen Benutzernamen ein.', 
         ), 
        ), 
       ), 
      ), 
     ); 
    } 
} 

एक नया उपयोगकर्ता

<?php 

namespace User\Form\Element; 

use Zend\InputFilter\InputProviderInterface; 
use User\Form\Element\Username; 

class CreateUsername extends Username implements InputProviderInterface 
{ 
    public function getInputSpecification() { 

     $spec = parent::getInputSpecification(); 
     $spec['validators'][] = array(
      'name' => 'Base\Validator\EntityUnique', 
      'options' => array(
       'message' => 'Der name %value% ist bereits vergeben.', 
       'entity' => 'User\Entity\User', 
       'attribute' => 'username', 
      ),  
     ); 

     return $spec; 
    } 
} 

बनाते समय जब एक मौजूदा उपयोगकर्ता

<?php 

namespace User\Form\Element; 

use Zend\InputFilter\InputProviderInterface; 
use User\Form\Element\Username; 

class EditUsername extends Username implements InputProviderInterface 
{ 
    protected $_userId; 

    public function __construct($userId) { 

     parent::__construct(); 
     $this->_userId = (integer)$userId; 
    } 

    public function getInputSpecification() { 

     $spec = parent::getInputSpecification(); 
     $spec['validators'][] = array(
      'name' => 'Base\Validator\EntityUnique', 
      'options' => array(
       'message' => 'Der name %value% ist bereits vergeben.', 
       'entity' => 'User\Entity\User', 
       'attribute' => 'username', 
       'exclude' => array(
        'attribute' => 'id', 
        'value' => $this->_userId, 
       ), 
      ),  
     ); 

     return $spec; 
    } 
} 
+0

तो आप स्थिर इकाई प्रबंधक कब सेट करते हैं?मुझे लगता है कि यह तब तक जाने का तरीका हो सकता है जब तक कि मैं ज़ेंडफ 2 को स्वयं बदलने की योजना नहीं बनाता। –

+0

मैं यह देखने के लिए इंतजार कर रहा हूं कि कोई भी अन्य प्रयासों को पोस्ट करता है लेकिन मुझे लगता है कि यह एक अच्छा विकल्प है। तुम्हारे काम के लिए धन्यवाद। एप्लिकेशन में –

+0

मैं इसे मॉड्यूल के module.php में सेट कर रहा हूं जिसमें सत्यापनकर्ता है और परीक्षण में मैं इसे testclass की सेटअप विधि में करता हूं। –

संबंधित मुद्दे