Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transform form field value in Symfony

Tags:

symfony

I'm using a table column to store "date_of_creation" (or created_at) in Unix timestamp format (basically an integer with length 11).

In the meanwhile I'd like to treat this value with DateTime format "d-m-Y" in my create/edit webform (Bootstrap Datepicker).

Here is the question:

What's the best way to convert and persist the value passed in DateTime format on a table column which is expecting to receive an integer and, viceversa, override the form field default value "timestamp format" with its corresponding DateTime format (to make it recognisable by DatePicker)?

I'm using Symfony 3.3.5 and Twig.

Here is an example:

I have used a workaround to reach the scope but I am not 100% sure it's a good practice...

The FormType.php add a text field with the class to hook the DatePicker widget:

->add('createdAt', TextType::class, [
            'attr' => [
                'class' => 'js-datepicker'
            ],
        ])

The Entity setter looks like that:

/**
 * @param mixed $createdAt
 */
public function setCreatedAt($createdAt, $stringToTime = true)
{
    $this->createdAt = ($stringToTime) ? strtotime($createdAt) : $createdAt;
}

The real trick here is the extra $stringToTime parameter.

And finally the controllerAction:

/**
 * @Route("/content/edit/{id}", name="admin_content_edit")
 */
public function editContentAction(Request $request, Content $content)
{
    $date = new \DateTime();
    $date->setTimestamp($content->getCreatedAt());
    $content->setCreatedAt($date->format('d-m-Y'), false);

    $form = $this->createForm(ContentType::class, $content);

    $form->handleRequest($request);
    if ($form->isSubmitted()){
        if ($form->isValid()) {

            $content = $form->getData();

            $em = $this->getDoctrine()->getManager();
            $em->persist($content);
            $em->flush();

            $this->addFlash('success', 'Content updated');

            return $this->redirectToRoute('admin_content_show');
        }
    }


    return $this->render('RootgearBundle:Default:editContent.html.twig', array(
        'contentForm' => $form->createView()
    ));
}

The key part is this:

$date = new \DateTime();
$date->setTimestamp($content->getCreatedAt());
$content->setCreatedAt($date->format('d-m-Y'), false);

This is what I have done and it works like a charm. But I don't know if it is the right approach or if there are better solutions.

Thanks in advance for very welcome remarks :)

============= NEW SOLUTION BASED ON SUGGESTION BY Alain Tiemblo

After reading a bit documentation about Data Transformer I finally figured out how to play with my "Date" value

I have applied changes only to my formType class by using CallbackTransformer and addModelTranformer object with closures.

That's the result which work like a charm as well :)

$builder->get('createdAt')
      ->addModelTransformer(new CallbackTransformer(
        function($dateTime) {
          $date = new \DateTime();
          $date->setTimestamp($dateTime);
          return $date->format('d-m-Y');
        },
        function($timestamp) {
          return $timestamp;
        }
      ));
like image 246
Fabrizio Sabato Avatar asked Aug 01 '17 16:08

Fabrizio Sabato


2 Answers

Good news, Symfony Data Transformers are exactly made for this!

When creating your form, you can add:

use Symfony\Component\Form\CallbackTransformer;

// (...)

$builder->get('createdAt')
    ->addModelTransformer(new CallbackTransformer(
        function ($dateModelToView) {
            $date = new \DateTime();
            $date->setTimestamp($dateModelToView);
            return $date;
        },
        function ($dateViewToModel) {
            return $dateViewToModel->getTimestamp();
        }
   ));

And transformation will be fully automatic.

like image 97
Alain Tiemblo Avatar answered Oct 21 '22 08:10

Alain Tiemblo


Usually you use some ORM (like doctrine) and you have DateTime field type for the database table, and the generated entities automatically treat them like DateTimes (html date picker on the front end).

You don't need to bother about it at all.

Here is an example: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html

Hope it helps.

like image 44
Keloo Avatar answered Oct 21 '22 07:10

Keloo