strange behavior on timestamp column

Table definition:

CREATE TABLE `demo` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL DEFAULT '',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

Model definition:

<?php
class Demo extends Model
{
    public function getSource()
    {
        return 'demo';
    }

    public function initialize()
    {
        $this->useDynamicUpdate(true);
    }
}

Test Code:

<?php
$demo = new Demo();
$demo->name = 'hello';
try {
      $demo->save();
      $demo->name = 'world';
      $demo->save();   //this line throw an exception with message:  created_at is required
} catch (\Exception $e) {
      echo $e->getMessage();
}

I confuse with it. Is this normal?

You set "NOT NULL" on all fields, which means they are required. phalcon orm validator checks that and throws an exception.

You set "NOT NULL" on all fields, which means they are required. phalcon orm validator checks that and throws an exception.

Wrong, he does have default values for the columns, they just cannot be nulled.

@zishon what are your SQL and Phalcon versions?

It's v3 or older version, because in v4 you can't use getSource() method. @zishon - yes, it's normal because when you maked some logic in database you need put some additional code in model.

  <?php
  class Demo extends Model
  {
      public function getSource()
      {
          return 'demo';
      }

      public function initialize()
      {
          $this->skipAttributesOnCreate(array('created_at', 'updated_at'));
          $this->useDynamicUpdate(true);
      }
  }


6.5k

i did some quick tests and found that after the first save created_at and updated_at are still null in the first object $date and didn't get upated with the default values. why is that ? this would require one of the experts here. i don't have the time to investigate at the moment.

uglyish solution to this:

$demo = new Demo();

$demo->name = 'hello';

$demo->save();

$demo = Demo::findFirst($demo->id);

$demo->name = 'world';

$demo->save();

Use:

$demo->create();

Instead of:

$demo->save();

Look at: https://docs.phalcon.io/3.4/en/db-models#createupdate-with-confidence

i did some quick tests and found that after the first save created_at and updated_at are still null in the first object $date and didn't get upated with the default values. why is that ? this would require one of the experts here. i don't have the time to investigate at the moment.

uglyish solution to this:

$demo = new Demo();

$demo->name = 'hello';

$demo->save();

$demo = Demo::findFirst($demo->id);

$demo->name = 'world';

$demo->save();
edited Jan '20

You set "NOT NULL" on all fields, which means they are required. phalcon orm validator checks that and throws an exception. mybkexperience



358

You set "NOT NULL" on all fields, which means they are required. phalcon orm validator checks that and throws an exception.

Wrong, he does have default values for the columns, they just cannot be nulled.

@zishon what are your SQL and Phalcon versions?

MySQL-5.6.42 Phalcon-3.4.1 PHP-7.2.11



358

It's v3 or older version, because in v4 you can't use getSource() method. @zishon - yes, it's normal because when you maked some logic in database you need put some additional code in model.

 <?php
 class Demo extends Model
 {
    public function getSource()
    {
        return 'demo';
    }

    public function initialize()
    {
        $this->skipAttributesOnCreate(array('created_at', 'updated_at'));
        $this->useDynamicUpdate(true);
    }
 }

It is the second save that throw the exception.



358

i did some quick tests and found that after the first save created_at and updated_at are still null in the first object $date and didn't get upated with the default values. why is that ? this would require one of the experts here. i don't have the time to investigate at the moment.

uglyish solution to this:

$demo = new Demo();

$demo->name = 'hello';

$demo->save();

$demo = Demo::findFirst($demo->id);

$demo->name = 'world';

$demo->save();

Yes, indeed, this is one of the solutions. Here is the second one.

<?php

$demo->save();
$demo->refresh();

In my opinion, phalcon should skip all validations on columns which have exact behaviors in table definition such as created_at, updated_at in this case.



358

Use:

$demo->create();

Instead of:

$demo->save();

I‘ve try this. It still throws exception with message: created_at is required

$demo->create_at = new \Phalcon\Db\RawValue('NULL');
if(!$demo->save()) {
    // handle errors
}

This will force the SQL engine to use the default value specified in the schema. If this works, you could handle this in the beforeUpdate method.



6.5k
edited Jan '20

I was looking at it all wrong. I don't know what was going on my mind that day.

in this case which is using created_at and updated_at as simply timestamps i would suggest using Model::skipAttributes() in the model

class Demo extends Model
{
    public function initialize()
    {
        $this->skipAttributes(['created_at','updated_at']);
    }
}

in other cases you may want to use the created object and get the newly added and maybe used a default value from mysql you have to use default value in the model itself because if you use Phalcon\Db\RawValue the problem is still there and for me i won't use Model::refresh()

for example if we set a default value for column name

CREATE TABLE IF NOT EXISTS `demo` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL DEFAULT 'hello world',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

if we create a new instance for Demo and saved immediately

$demo = new Demo;
$demo->save(); // returns true
$demo->name; // still null
$demo->created_at; // still null but its not the case

so the best bet here is to set a default value in the model class

class Demo extends \Phalcon\Mvc\Model
{
    public $id;

    public $name = 'hello world';

    public $created_at;

    public $updated_at;

    public function initialize()
    {
        $this->skipAttributes(['created_at','updated_at']);
    }
}
$demo = new Demo;
$demo->save(); // returns true
$demo->name; // hello world
$demo->created_at; // null

Thank you guys, it's very relevant for me now!!

facing the same problem of strange behaviour on timestamp column I think Phalcon should bypass all validations on columns that have specific behaviors in desk definition anyways seeking for a fine solution.