5

I'm trying to cast an entity property into an array so that it autoserializes.

The Entity is set up as follows

\App\Entities\Submission.php

<?php

namespace App\Entities;
use CodeIgniter\Entity;

class Submission extends Entity
{

 protected $casts =[
   'field2' => 'array'
 ];

}

Then in a controller I create a new entity, filling it using the constructor

<?php
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];

$submission = new \App\Entities\Submission($allowedFromPost);
?>

Dumping the submission at this point (var_dump()) shows field2 being an array, it's not serialised.

 ["attributes":protected]=>
  array(2) {
    ["field1"]=>
    string(6) "value1"
    ["field2"]=>
    array(2) {
      [0]=>
      int(0)
      [1]=>
      int(1)
    }
  }

if I do

$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];

$submission = new \App\Entities\Submission($allowedFromPost);
$submission->field2 = $submission->field2;

and then var_dump, field2 is correctly serialised.

  ["attributes":protected]=>
  array(2) {
    ["field1"]=>
    string(6) "value1"
    ["field2"]=>
    string(22) "a:2:{i:0;i:0;i:1;i:1;}"
  }

For some reason, it seems like filling using the constructor does not autoserialize, I have to manually set the field. Am I doing something wrong?

The problem this caused is that when I tried inserting that entity into the Database, it threw an error saying

"mysqli_sql_exception Operand should contain 1 column(s)"

which went away when I flattened the array (first by dropping all but one values to test and then by using what I've done above)

================
EDIT 11/05: This turned out to be an issue on the core code. fill() (and the constructor) were not configured to use __set() so autoserialization was not happening. See the PR on Codeigniter's Github page here.
I'll be accepting Kulshreshth K's answer because, for now, this provides an adequate workaround but in the future it will most likely not be needed.

  • I guess the value is serialized only when it is "rendered". `var_dump()` is showing the inner content of the php object which is not serialized. The serialization happens when you read this property and when you perform the next assignment you decide to overwrite the current content of the property (the array) with its rendered value (the string of this serialized array). – Tuckbros May 11 '20 at 12:36
  • Generally yes, that's how it works. Specifically when casting as 'array','json',or 'json_array' however, serialization (or encoding) happens on set and then when you read the variable it deserializes it(or decodes it respectivelly). Check my edit, this should be fixed in the future. – Constantine Loukas May 11 '20 at 14:58

1 Answers1

0

Add this in your Entity:

public function __construct($arr) {
   $this->field2 = $arr['field2'];
}

Controller:

$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];

$submission = new \App\Entities\Submission($allowedFromPost);
var_dump($submission)

Result:

["attributes":protected]=>
  array(2) {
    ["field1"]=>
    string(6) "value1"
    ["field2"]=>
    string(22) "a:2:{i:0;i:0;i:1;i:1;}"
  }

As per CI documentation you need to set it after initialize its model anyway:

<?php namespace App\Entities;

use CodeIgniter\Entity;

class User extends Entity
{
    protected $casts => [
        'options' => 'array',
                'options_object' => 'json',
                'options_array' => 'json-array'
    ];
}

$user    = $userModel->find(15);
$options = $user->options;

$options['foo'] = 'bar';

$user->options = $options;
$userModel->save($user);
Kulshreshth K
  • 1,096
  • 1
  • 12
  • 28
  • The issue remains, field2 should be automatically be serialized when set (as per the CI docs) but it is not. Both your solution and mine essentially set the property twice, you do it in the constructor, I do it after creating the Entity. – Constantine Loukas May 05 '20 at 08:25
  • Did you try to use the model and save data? maybe it will work then when saving in DB. – Kulshreshth K May 05 '20 at 08:48
  • Yes, without doing the fix (simply creating the submission and doing $submissionsModel->save($submission)) results in the error I described in my post. Again without the fix, if instead of an array I set $field2 to be a string the submission is saved in the DB. To insert the array into the db I have to do the fix I described above (setting $this->field2 = $this->field2) – Constantine Loukas May 05 '20 at 09:26