1
votes

What I'm trying to do is to set a "seoUpdatedAt" field when the "pageTitle" or "metaDescription" fields are modified. In the same time I'd like to render the content of this field in my backoffice through the Symfony2 form component, without giving the possibility to edit the field value (because the value must be set up by the timestampable extension).

I tried to set up the field as *read_only* but the value doesn't update, and neither does the doctrine extension (as though it is being ignored and it makes sense).

I also tried to set the field as a *datetime single_text* but two problems arose:

  1. the admin can manually change the value
  2. right after the submit action takes place the value that is rendered appears to be the old datetime although it's been updated on the DB side, as though the value in the POST request is overwriting the DB value in the form rendering flow. refreshing the page without resubmitting the data shows the updated value (updated by the doctrine extension)

I finally tried with the disabled option but it's not working as expected.

A pinch of code:

// in my entity

/**
 * @var \DateTime
 * @Gedmo\Timestampable(on="change", field={"pageTitle", "metaDescription"})
 * @ORM\Column(name="seo_updated_at", type="datetime", nullable=true)
 */
private $seoUpdatedAt;

And here the form:

// in my form type

$builder
    ->add('pageTitle', 'text', array('required' => false))
    ->add('metaDescription', 'textarea', array('required' => false))
    ->add(
        'seoUpdatedAt',
        'datetime',
        array(
            'widget' => 'single_text',
            'format' => 'dd-MM-yyyy HH:mm:ss',
            'required' => false
        )
    );

So, how do you suggest meeting the following requirements?

  • the value shouldn't be manually editable
  • the value must be always rendered with the updated value even after a form submission

Listener on Doctrine events? Listener on a form event? A new form type extension?

3

3 Answers

1
votes

Try this: in your entity add an empty setter method for $seoUpdatedAt:

/**
 * @var \DateTime
 * @Gedmo\Timestampable(on="change", field={"pageTitle", "metaDescription"})
 * @ORM\Column(name="seo_updated_at", type="datetime", nullable=true)
 */
private $seoUpdatedAt;

public function setSeoUpdatedAt(\DateTime $seoUpdatedAt)
{
    //empty
}

and in your form builder object add the 'by_reference' option in the seoUpdatedAt definition:

$builder
    ->add('pageTitle', 'text', array('required' => false))
    ->add('metaDescription', 'textarea', array('required' => false))
    ->add(
        'seoUpdatedAt',
        'datetime',
        array(
            'widget' => 'single_text',
            'format' => 'dd-MM-yyyy HH:mm:ss',
            'required' => false,
            'by_reference' => false,
        )
    );
0
votes

I cannot provide much sample code because I don't know Symfonie (I'm working with ZF).

Look at the onPrePerstist or onPreUpdate events:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#lifecycle-events

http://symfony.com/doc/current/book/doctrine.html

It goes something like this:

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 */
class YourClass



/**
 * @ORM\PrePersist
 * @ORM\PreUpdate
 */
public function updateChanged() {
    $this->updated = new \DateTime();
}

Whenever you update a field, it calls the pre* method and updates your column.

Update:

Why not something like:

public function setMetaDescription($metaDescription) {
    $this->metaDescription = $metaDescription;
    $this->setUpdatedAt    = new \DateTime();
}

So whenever the field gets updated, it also updates the datetime column.

0
votes

Solved by removing the timestampable field from the form. I render it fetching by the data directly from the pagination object.

In that way the application meets all the requirements:

  • the datetime field is updated by the timestampable extension
  • the datetime value is always rendered with its current value even after a form submission
  • the datetime value can't be changed through the web interface

I hope this might help someone else.