mysqljsoncakephpcakephp-3.3

Cake 3: column of type JSON stores a NULL as string "null"


My model is defined as follows:

<?php
namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\Database\Schema\Table as Schema;

class AppLogsTable extends Table
{    
    protected function _initializeSchema(Schema $schema) {
        $schema->columnType('data', 'json');
        return $schema;
    }       
}

The JSON format is correctly applied when saving into database and when retrieving data. However, if I set $appLog->data = null and save it through $this->appLogs->save($appLog) it would save a string null into the database rather than a real NULL value. The colum data in the app_logs table is set to accept nulls.

If I uncomment the column type definition, it stores nulls correctly.

How to keep the automatic JSON data type and store NULL correctly from the model?


Solution

  • You'll have to use a custom/extended database type class that handles null values accordingly, the built-in one will pass everything through json_encode() no matter what.

    Something along the lines of this:

    // src/Database/Type/NullAwareJsonType.php
    
    namespace App\Database\Type;
    
    use Cake\Database\Driver;
    use Cake\Database\Type\JsonType;
    
    class NullAwareJsonType extends JsonType
    {
        public function toDatabase($value, Driver $driver)
        {
            if ($value === null) {
                return null;
            }
    
            return parent::toDatabase($value, $driver);
        }
    }
    

    You can then either override the built in json type:

    // config/bootstrap.php
    
    \Cake\Database\Type::map('json', \App\Database\Type\NullAwareJsonType::class);
    

    or map it as a new type and set the column type accordingly:

    \Cake\Database\Type::map('nullAwareJson', \App\Database\Type\NullAwareJsonType::class);
    
    $schema->columnType('data', 'nullAwareJson');
    

    See also