Doctrine 1
  1. Doctrine 1
  2. DC-1051

Timestampable listener does not set timestamp fields on a copy of a Doctrine_Record

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.2.3
    • Fix Version/s: None
    • Component/s: Timestampable
    • Labels:
      None

      Description

      The Timestampable Listener only sets the timestamp if the timestamp field has not been modified:

      if ( ! isset($modified[$createdName])) {
        $event->getInvoker()->$createdName = $this->getTimestamp('created', $event->getInvoker()->getTable()->getConnection());
      }
      

      When saving a copy of a Doctrine_Record that doesn't already have the timestamp fields set fails to be updated, leading to integrity constraint violation ("created_at cannot be NULL"). The reason is that all unset fields in the copy are set to an instance of Doctrine_Null, which is considered to be modifed according to the condition tested for above. To fix the issue, I modified the code above to read:

      if ( ! isset($modified[$createdName]) || $modified[$createdName] instanceof Doctrine_Null) {
        $event->getInvoker()->$createdName = $this->getTimestamp('created', $event->getInvoker()->getTable()->getConnection());
      }
      

        Activity

        Hide
        blopblop added a comment - - edited

        Your fix works great, I have also added the fix for the preupdate function and in one more place in the preinsert function.
        Lines affected: 65, 73, 91.
        Attached the file with the fixes:
        ( C:\php5\PEAR\symfony\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Template\Listener\Timestampable.php )

        [code]
        /**

        • Set the created and updated Timestampable columns when a record is inserted
          *
        • @param Doctrine_Event $event
        • @return void
          */
          public function preInsert(Doctrine_Event $event)
          {
          if ( ! $this->_options['created']['disabled'])
          Unknown macro: { $createdName = $event->getInvoker()->getTable()->getFieldName($this->_options['created']['name']); $modified = $event->getInvoker()->getModified(); if ( ! isset($modified[$createdName]) || $modified[$createdName] instanceof Doctrine_Null) { $event->getInvoker()->$createdName = $this->getTimestamp('created', $event->getInvoker()->getTable()->getConnection()); } }

        if ( ! $this->_options['updated']['disabled'] && $this->_options['updated']['onInsert']) {
        $updatedName = $event->getInvoker()>getTable()>getFieldName($this->_options['updated']['name']);
        $modified = $event->getInvoker()->getModified();
        if ( ! isset($modified[$updatedName]) || $modified[$updatedName] instanceof Doctrine_Null)

        { $event->getInvoker()->$updatedName = $this->getTimestamp('updated', $event->getInvoker()->getTable()->getConnection()); }
        }
        }

        /**
        * Set updated Timestampable column when a record is updated
        *
        * @param Doctrine_Event $evet
        * @return void
        */
        public function preUpdate(Doctrine_Event $event)
        {
        if ( ! $this->_options['updated']['disabled']) {
        $updatedName = $event->getInvoker()>getTable()>getFieldName($this->_options['updated']['name']);
        //echo "updatedName: "; var_dump(updatedName);
        $modified = $event->getInvoker()->getModified();
        if ( ! isset($modified[$updatedName]) || $modified[$updatedName] instanceof Doctrine_Null) { $event->getInvoker()->$updatedName = $this->getTimestamp('updated', $event->getInvoker()->getTable()->getConnection()); }

        }
        }
        [/code]
        ------------------

        Also there is another problem too. If you dont disable the widgets of the fields updated_at and created_at, sometimes they are sending the date time information in the $form, and the function preUpdate doesnt update the update_at because the date time has been sent. The best option is to disable the widgets and form validation in global scope, here:
        <?php

        /**

        • Project form base class.
          *
        • @package dbvui
        • @subpackage form
        • @author Your name here
        • @version SVN: $Id: sfDoctrineFormBaseTemplate.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $
          */
          abstract class BaseFormDoctrine extends sfFormDoctrine
          {
          public function setup()
          {
          //Following code will remove Required validators from these fields.
          if (isset($this->validatorSchema))
          {
          if (isset($this->validatorSchema['created_at'])) { unset($this->validatorSchema['created_at']); }

        if (isset($this->validatorSchema['updated_at']))

        { unset($this->validatorSchema['updated_at']); }

        }

        if (isset($this->widgetSchema))
        {
        //following code will remove fields from form
        if (isset($this->widgetSchema['created_at']))

        { unset($this->widgetSchema['created_at']); }

        if (isset($this->widgetSchema['updated_at']))

        { unset($this->widgetSchema['updated_at']); }

        }
        }
        }

        Show
        blopblop added a comment - - edited Your fix works great, I have also added the fix for the preupdate function and in one more place in the preinsert function. Lines affected: 65, 73, 91. Attached the file with the fixes: ( C:\php5\PEAR\symfony\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Template\Listener\Timestampable.php ) [code] /** Set the created and updated Timestampable columns when a record is inserted * @param Doctrine_Event $event @return void */ public function preInsert(Doctrine_Event $event) { if ( ! $this->_options ['created'] ['disabled'] ) Unknown macro: { $createdName = $event->getInvoker()->getTable()->getFieldName($this->_options['created']['name']); $modified = $event->getInvoker()->getModified(); if ( ! isset($modified[$createdName]) || $modified[$createdName] instanceof Doctrine_Null) { $event->getInvoker()->$createdName = $this->getTimestamp('created', $event->getInvoker()->getTable()->getConnection()); } } if ( ! $this->_options ['updated'] ['disabled'] && $this->_options ['updated'] ['onInsert'] ) { $updatedName = $event->getInvoker() >getTable() >getFieldName($this->_options ['updated'] ['name'] ); $modified = $event->getInvoker()->getModified(); if ( ! isset($modified [$updatedName] ) || $modified [$updatedName] instanceof Doctrine_Null) { $event->getInvoker()->$updatedName = $this->getTimestamp('updated', $event->getInvoker()->getTable()->getConnection()); } } } /** * Set updated Timestampable column when a record is updated * * @param Doctrine_Event $evet * @return void */ public function preUpdate(Doctrine_Event $event) { if ( ! $this->_options ['updated'] ['disabled'] ) { $updatedName = $event->getInvoker() >getTable() >getFieldName($this->_options ['updated'] ['name'] ); //echo "updatedName: "; var_dump(updatedName); $modified = $event->getInvoker()->getModified(); if ( ! isset($modified [$updatedName] ) || $modified [$updatedName] instanceof Doctrine_Null) { $event->getInvoker()->$updatedName = $this->getTimestamp('updated', $event->getInvoker()->getTable()->getConnection()); } } } [/code] ------------------ Also there is another problem too. If you dont disable the widgets of the fields updated_at and created_at, sometimes they are sending the date time information in the $form, and the function preUpdate doesnt update the update_at because the date time has been sent. The best option is to disable the widgets and form validation in global scope, here: <?php /** Project form base class. * @package dbvui @subpackage form @author Your name here @version SVN: $Id: sfDoctrineFormBaseTemplate.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $ */ abstract class BaseFormDoctrine extends sfFormDoctrine { public function setup() { //Following code will remove Required validators from these fields. if (isset($this->validatorSchema)) { if (isset($this->validatorSchema ['created_at'] )) { unset($this->validatorSchema['created_at']); } if (isset($this->validatorSchema ['updated_at'] )) { unset($this->validatorSchema['updated_at']); } } if (isset($this->widgetSchema)) { //following code will remove fields from form if (isset($this->widgetSchema ['created_at'] )) { unset($this->widgetSchema['created_at']); } if (isset($this->widgetSchema ['updated_at'] )) { unset($this->widgetSchema['updated_at']); } } } }
        Hide
        blopblop added a comment -

        fixed

        Show
        blopblop added a comment - fixed

          People

          • Assignee:
            Jonathan H. Wage
            Reporter:
            Jeremy Johnson
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated: