user4827782
user4827782

Reputation:

How to add a custom hydrator strategy for doctrine Date hydrator

I have a form which contains 3 field of type text and with a Date validator.

This code is in a fieldset using doctrine hydrator (related to a doctrine entity)

$this->add(
        array(
            'name' => 'endDate',
            'type' => 'Zend\Form\Element\Text',
            'options' => array(
                'label' => 'end_date_label',
                'label_attributes' => array(
                    'class'  => 'control-label col-xs-3'
                ),
            ),
            'attributes' => array(
                'class' => 'form-control col-xs-3 datepicker-end-date',
            )
        )
    );


'endDate' => array(
        'required'   => true,
        'allow_empty' => false,
        'filters'    => array(
            array('name' => 'StripTags'),
            array('name' => 'StringTrim'),
        ),
        'validators' => array(
            array(
                'name' => 'Date',
                'options' => array(
                    'format' => 'd/m/Y',
                ),
            ),
        ),
    ),

I working with french date format. When i valid the form if i change the format to m/d/Y it's working but when my form is not valid, my date picker get the wrong date (month and days are inversed).

What i want is to valid a french date format, and save into Database a date in m/d/Y format.

With this format i get the error :

DateTime::__construct(): Failed to parse time string (29/04/2015) at position 0 (2): Unexpected character

I saw many post on Stack talking about custom strategy for doctrine hydration but i didn't understand them. What i'm supposed to do step by step ?

I tried to add a strategy for my field endDate but it's never called...This code is in the fieldset class just before my fields declaration :

$this->setHydrator(new DoctrineHydrator($this->getObjectManager(), 'TodoList\Entity\TodoQuestion'))
            ->setObject(new TodoQuestion());
        $this->getHydrator()->addStrategy('endDate', new \Application\Strategy\DateTimeStrategy());

And my Datetime strategy implements strategy interface.

<?php

namespace Application\Strategy;

use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;

class DateTimeStrategy implements StrategyInterface
{
    public function hydrate($value)
    {
        if (is_string($value)) {
            $value = new DateTime($value);
        }
        return $value->format('d/m/Y');
    }

    public function extract($value)
    {
        return;
    }
}

If someone can explain with details what i'm doing wrong and help me to understand this whole thing..

Upvotes: 0

Views: 1493

Answers (2)

rkeet
rkeet

Reputation: 3468

Stumbled onto this question by accident. Though it's reasonably old, I was recently working with Dates in ZF2 forms. I've got my formatting done as below, without using a callback.

Maybe it'll help someone in the future ;)

Below was done using ZF2 2.5.3

    $this->add([
        'name' => 'startDate',
        'required' => true,
        'filters' => [
            [
                'name' => DateTimeFormatter::class,
                'options' => [
                    'format' => 'Y-m-d', // or d/m/Y
                ],
            ],
        ],
        'validators' => [
            [
                'name' => Date::class,
                'options' => [
                    'format' => 'Y-m-d', // or d/m/Y
                ],
            ],
        ],
    ]);

Upvotes: 0

netiul
netiul

Reputation: 2769

You should just return a DateTime object from the Strategy.

namespace Application\Strategy;

use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;

class DateTimeStrategy implements StrategyInterface
{
    public function hydrate($value)
    {
        if (is_string($value)) {
            $value = \DateTime::createFormFormat('d/m/Y', $value);
        }
        return $value;
    }

    public function extract($value)
    {
        return $value;
    }
}

Above isn't going to work since strategies are called after the hydrator's type conversion.

You're best of with using a Callback filter.

'endDate' => array(
    'required'   => true,
    'allow_empty' => false,
    'filters'    => array(
        array('name' => 'StripTags'),
        array('name' => 'StringTrim'),
        array(
            'name' => 'Callback',
            'options' => array(
                'callback' => function($value) {
                    if (is_string($value)) {
                        $value = \DateTime::createFromFormat('d/m/Y', $value);
                    }
                    return $value;

                },
            ),
    ),
    'validators' => array(
        array(
            'name' => 'Date',
            'options' => array(
                'format' => 'd/m/Y',
            ),
        ),
    ),
),

The doctrine hydrator you are using seems outdated btw. Current version doesn't require to specify the entity as a second parameter.

Upvotes: 1

Related Questions