We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Phalcon\Mvc\Model could not insert an empty string ?

This is the model class

class Mails extends \Phalcon\Mvc\Model {
    public static function newMail($sender, $receiver, $type, $content = '') {
        $mail = new Mails ();
        $mail->src_id = $sender;
        $mail->dst_id = $receiver;
        $mail->type = $type;
        $mail->content=$content,
        $mail->when=time();
        $mail->status='unread';
        $mail->save();
    }
}

table definition:

CREATE TABLE `mails` (
  `email_id` int(12) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `src_id` int(22) NOT NULL COMMENT '发送者',
  `dst_id` int(22) NOT NULL COMMENT '接收者',
  `type` enum('other','request','gift','text') NOT NULL DEFAULT 'text' COMMENT '类型',
  `content` varchar(512) NOT NULL DEFAULT '' COMMENT '内容',
  `when` int(12) NOT NULL DEFAULT '0' COMMENT '发送时间戳',
  `status` enum('none','deleted','accepted','read','unread') NOT NULL DEFAULT 'none' COMMENT '状态',
  PRIMARY KEY (`email_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

when I call:

Mails::newMail('123','321','text');

I got a 'content is required' but in debug windows, $content is an empty string , NOT a NULL.



51.1k

"content is required" is a validation error. Do you have any validators in the model ?



1.2k

Generally I don't like your logic.

  1. Why do you call self-class instance twice ?
  2. Make condition whether content is not equal to empty.
  3. "when" column can be set from mysql or model events such like beforeSave();
class Mails extends Model {
    public function beforeSave() {
        $this->when = time();
    }

    //...
}

or

`when` int(12) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发送时间戳',

but this not saves UNIX_TIMESTAMP format, this saves YYYY-MM-DD HH:MM:SS

  1. If you don't want to make condition for content, you may use
public function initialize() {
    $this->skipAttributesOnCreate(array('content'));
}

public static function newMail(..., $content = null) {
    if ( !empty($content) ) 
        $this->content = $content;

    // the others columns
}

this should skip this column if it's not set something on it and would get default value from mysql.

Another reason is that @calinrada tell you before me.



17.8k

@relax4o

  1. the twice calling of constructor is my mistack.
  2. the content field only be empty when needed, and in this situation, it should be empty.
  3. the when field is not always be the current timestamp, so i dont put it into the beforeSave

my really question is that i what put an empty string into content field and save it to the database. and i dont have any validator on Mails. i want to know is there a way to do that.

extra question: will the skipAttributeOnCreate method ignore the content field every time on inserting ?



1.2k
Accepted
answer
edited Aug '14

Yes, now I read the documentation. It will always skip this column. But you can do something else - to use \Phalcon\Db\RawValue('default');

if ( empty($content) ) {
    $content = \Phalcon\Db\RawValue('default');
}

$this->content = $content;

so if your content is empty you will take the default value from mysql. If it's not empty, should ignore this condition and go ahead with the code.

I am not sure whether you may do this:

function newMail(...., $content = \Phalcon\Db\RawValue('default'))

if it possible, you can save one condition into the function.

Why can't you allow content to be ALLOW NULL in database?



1.2k

This wouldn't work. I have columns which are ALLOW NULL, but Phalcon looking for them again and throwing errors.



17.8k
edited Aug '14

Thanks to @relax4o, problem was cleared by


new \Phalcon\Db\RawValue('default')  

, and how about the



new \Phalcon\Db\RawValue('') 

``` ?


1.2k

I am not sure, but you can try. There is no info in documentation.

Never use a \Phalcon\Db\RawValue to assign external data (such as user input) or variable data. The value of these fields is ignored when binding parameters to the query. So it could be used to attack the application injecting SQL.

It should take the value, but try for sure.



98.9k

It must be:

new \Phalcon\Db\RawValue("''");

Hi there,

Isn't it a bit heavy to write "new \Phalcon\Db\RawValue("''");" instead of simply "''"?

As requested here https://github.com/phalcon/cphalcon/issues/440, I tend to agree with the numerous people asking for this change: empty string is not a NULL value in MySQL (and it is not in PHP either, whereas it is considered a "falsy" value). Therefore, a field which is "NOT NULL" should allow empty strings, which are completely valid values.

As for the "trim()" explanation found in the bugfix request, I do not agree: it is up to applications to check for input, no matter what. The database abstraction layer should not make assumptions of the application code, and should strictly stick to the database expected behavior, which would be to allow the empty string value (often used for "description" columns, for example).

Please, I humbly ask you to reconsider this, as it is highly counter-intuitive and degrade the code lisibility.

A bump :

This "feature" breaks my application...

I am migrating an application to Phalcon, but I have several fields in several tables that do not allow NULL values, but allow empty string (because empty string is not a NULL value). And now everywhere a save() is done, my application breaks.

If your first answer would have been "it is poor design in your application" then first of all I did not design it (which is why it is so much important to remove this "feature" because it breaks portability), and secondly since MySQL allows it, I really do not understand why you are battling against it.

Please, stop this nonsense and allow empty string as a valid non-null value... Because it is!

Thanks in advance for your understanding,

A Phalcon adept

PS : the forum is still mega slow when typing a long message :-/

edited Jun '15

This is making my edit forms to contain '' when i open them back up in edit mode instead of being blank. and showing the placeholder.

It must be:

new \Phalcon\Db\RawValue("''");