zend框架2学说水合策略 - 水合物方法从未被称为

时间:2013-10-14 09:17:23

标签: php doctrine-orm zend-framework2

我目前正在开展涉及Zend Framework 2和Doctrine的项目。

我正在实现一个Zend \ Form并使用DoctrineORMModule \ Stdlib \ Hydrator \ DoctrineEntity从数据库中提取和水合数据。

在我读过的大部分教程中,当你需要在保湿对象之前转换特定值时,理想的是实现Zend \ Stdlib \ Hydrator \ Strategy \ StrategyInterface(在我的例子中是一个日期时间值字符串,这是使用Doctrine时的一个问题)。然而,尽管我尽最大努力实现这一点,但似乎只调用了我的水合策略中的extract()方法,而不是水合()方法。 EVER!

为了提供一个代码示例,这就是我正在做的事情 - 为了简洁,我缩短了代码的某些方面;

// Service

public function getProposerForm() {

    // get required classes from service manager

    $proposerEntity = $this->getServiceManager()->get('tourers_entity_proposer');

    $entityManager = $this->getServiceManager()->get('Doctrine\ORM\EntityManager');

    $formManager = $this->getServiceManager()->get('FormElementManager');
    $proposerFieldset = $formManager->get('tourers_form_proposer_fieldset');
    $proposerForm = $formManager->get('tourers_form_proposal');


    $proposerFieldset->setUseAsBaseFieldset(true);
    $proposerForm->add($proposerFieldset);

    $proposerForm->get('submit')->setValue('Continue');
    $proposerForm->bind($proposerEntity);

    return $proposerForm;
}

// Controller

public function proposerAction() {    

    // grab the form from the form service

   $formService = $this->getServiceLocator()->get('tourers_service_forms');

   $form = $formService->getProposerForm();

    if (true === $this->getRequest()->isPost()) {

        $form->setData($this->getRequest()->getPost());

        if (true === $form->isValid()) {

            $proposerEntity = $form->getData();

            $encryptedPolicyId = $formService->saveProposerForm($proposerEntity, $policyId);

            return $this->redirect()->toRoute('tourers/proposal/caravan',array('policyid' => $encryptedPolicyId));


        } else {
            $errors = $form->getMessages();
            var_dump($errors);
        }
    }

    // view

    return new ViewModel(array(
        'form'      =>  $form
        ,'policyid' =>  $policyId
        )
    );

}

// Form

class ProposerFieldset extends Fieldset implements InputFilterProviderInterface, ObjectManagerAwareInterface
{

/**
 * @var Doctrine\ORM\EntityManager
 */
private $objectManager;

/**
 * @return Zend\Form\Fieldset
 */

public function init()
{
    // set name

    parent::__construct('Proposer');

    // set the hydrator to the domain object

    $hydrator = new DoctrineEntity($this->objectManager,true);
    $hydrator->addStrategy('proposerDateOfBirth',new DateStrategy);

    $this->setHydrator($hydrator);

    // other form elements below here including proposerDateOfBirth

    $minDate = date('dd\/mm\/yyyy',strtotime('-100 years'));
    $maxDate = date('dd\/mm\/yyyy',strtotime('-16 years'));

    $this->add(array(
        'name'  => 'proposerDateOfBirth'
        ,'type'  => 'Zend\Form\Element\Date'
        ,'attributes' => array(
            'class' => 'form-control'
            ,'id' => 'proposerDateOfBirth'
            ,'placeholder' => 'dd/mm/yyyy'
            ,'min' => $minDate
            ,'max' => $maxDate
            ,'data-date-format' => 'dd/mm/yyyy'

        ),
        'options' => array(
            'label' => 'Date of Birth',
        )
    ));
}
}

// Hydrator Strategy

namespace Tourers\Hydrator\Strategy;

use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;

class DateStrategy implements StrategyInterface {

/**
* (non-PHPdoc)
* @see Zend\Stdlib\Hydrator\Strategy.StrategyInterface::extract()
*/
public function extract($value) {
    var_dump($value . ' extracted'); // GETS CALLED
    return $value;

}

/**
 * (non-PHPdoc)
 * @see Zend\Stdlib\Hydrator\Strategy.StrategyInterface::hydrate()
 */
public function hydrate($value) {
    var_dump($value . ' hydrated'); // NEVER CALLED
    return $value;
}
}

1 个答案:

答案 0 :(得分:2)

我也发现了这种行为。至于为什么我的自定义策略没有被调用,我仍然感到很遗憾。

策略应用于 hydrateValue() extractValue()函数中,因此 hydrate()<需要调用这些函数/ strong>和 extract()函数,以便应用策略或自定义策略。

我的问题在DoctrineModule \ Stdlib \ Hydrator \ DoctrineObject中的 hydrateByReference()函数中很明显。

似乎 $ this-&gt; hydrateValue(...)仅被称为字段“ associations ”。我还不知道这些“ association ”是什么,或者我错误地认为它们不存在于我的数据中。

当我将它与 extractByReference()函数进行比较时,我注意到它总是调用 $ this-&gt; extractValue(),并且不需要任何“协会”。

在我的应用程序中,我已经实现了一个自定义的 Hydrator 类。这意味着当我创建表单时,会自动应用Hydrator和Strategies。

  • 在我的表单的 init()功能中,我指定了自定义Hydrator。
  • 在我的Custom Hydrator的 __ construct()中,我添加了策略和自定义策略。


所以我需要做的就是在我的Custom Hydrator中覆盖 hydrateByReference(...)来解决问题。示例如下。

注意:

  1. 如果您使用“ by value ”水合作用,您可能还需要覆盖 hydrateByValue(...)
  2. 我的解决方案可能会破坏“ association ”的功能。

  3. My Custom Hydrator课程:

    class maintenance 
            extends DoctrineHydrator
    {
    
    
        /**
         * Constructor
         *
         * @param ObjectManager $objectManager The ObjectManager to use
         */
        public function __construct($objectManager)
        {
            /*
             * Just call the parent class.
             */
            parent::__construct($objectManager, 
                    'Maintenance\Entity\maintenance',  // The FQCN of the hydrated/extracted object
                    false                               // If set to true, hydrator will always use entity's public API
                );
    
    
            /*
             * Now set up our strategies, and attach them 
             * to the appropriate fields.
             */
            $this->addStrategy('purchasedate', new TIGDateStrategy());
            $this->addStrategy('maintexpirydate', new TIGDateStrategy());
    
        }
    
        /**
         * SF Modification, to ensure we call this->hydrateValue on
         * all values before doing anything else with the data.
         * This way, we convert the data first, before trying to
         * store it in a DoctrineEntity.
         * 
         * Hydrate the object using a by-reference logic (this means that values are modified directly without
         * using the public API, in this case setters, and hence override any logic that could be done in those
         * setters)
         *
         * @param  array  $data
         * @param  object $object
         * @return object
         */
        protected function hydrateByReference(array $data, $object)
        {
            $object   = $this->tryConvertArrayToObject($data, $object);
            $metadata = $this->metadata;
            $refl     = $metadata->getReflectionClass();
    
            foreach ($data as $field => $value) {
                // Ignore unknown fields
                if (!$refl->hasProperty($field)) {
                    continue;
                }
    
                // SF Mod
                $value = $this->hydrateValue($field, $value);
                // End SF Mod
    
                $value        = $this->handleTypeConversions($value, $metadata->getTypeOfField($field));
                $reflProperty = $refl->getProperty($field);
                $reflProperty->setAccessible(true);
    
                if ($metadata->hasAssociation($field)) {
                    $target = $metadata->getAssociationTargetClass($field);
    
                    if ($metadata->isSingleValuedAssociation($field)) {
                        $value = $this->toOne($target, $this->hydrateValue($field, $value));
                        $reflProperty->setValue($object, $value);
                    } elseif ($metadata->isCollectionValuedAssociation($field)) {
                        $this->toMany($object, $field, $target, $value);
                    }
                } else {
                    $reflProperty->setValue($object, $value);
                }
            }
    
            return $object;
        }
    
    }