You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Try to serialize an active record which has a datetime column with its default value
What's expected?
Serialize the object and then successfully unserializing it.
What do you get instead?
When you try to unserialize, you get an error because yii\db\Expression is missing required parameters in the constructor
Additional info
I have an idea to use reflection to get around the issue. Of course it will only work if the parameters are public properties. I will post here if it works.
<?php
class JsonSerializer extends \yii\queue\serializers\JsonSerializer
{
public $constructorParamsKey = 'constructorParams';
/**
* @param mixed $data
* @return array|mixed
* @throws InvalidConfigException
*/
protected function toArray($data)
{
if (is_object($data)) {
$result = [$this->classKey => get_class($data)];
foreach (get_object_vars($data) as $property => $value) {
if ($property === $this->classKey) {
throw new InvalidConfigException("Object cannot contain $this->classKey property.");
}
if ($property === $this->constructorParamsKey) {
throw new InvalidConfigException("Object cannot contain $this->constructorParamsKey property.");
}
$result[$property] = $this->toArray($value);
}
$constructorParams = $this->getConstructorParams($data);
if(!empty($constructorParams)){
$result['constructorParams'] = $constructorParams;
}
return $result;
}
if (is_array($data)) {
$result = [];
foreach ($data as $key => $value) {
if ($key === $this->classKey) {
throw new InvalidConfigException("Array cannot contain $this->classKey key.");
}
$result[$key] = $this->toArray($value);
}
return $result;
}
return $data;
}
/**
* @param array $data
* @return mixed
*/
protected function fromArray($data)
{
if (!is_array($data)) {
return $data;
}
if (!isset($data[$this->classKey])) {
$result = [];
foreach ($data as $key => $value) {
$result[$key] = $this->fromArray($value);
}
return $result;
}
$config = ['class' => $data[$this->classKey]];
unset($data[$this->classKey]);
$constructorParams = [];
if(isset($data['constructorParams'])){
$constructorParams = $data['constructorParams'];
unset($data['constructorParams']);
}
foreach ($data as $property => $value) {
$config[$property] = $this->fromArray($value);
}
return Yii::createObject($config, $constructorParams);
}
/**
* Returns the constructor params and their values
* @param $object
* @return array
*/
protected function getConstructorParams($object)
{
$ref = new ReflectionClass($object);
if (!$ref->isInstantiable()) {
return [];
}
$parameters = [];
$constructor = $ref->getConstructor();
$params = $constructor->getParameters();
foreach ($params as $param) {
$name = $param->getName();
if(property_exists($object, $name)) {
$parameters[] = $object->{$name};
}
}
return $parameters;
}
}
Q
A
Yii version
2.0.15.1
PHP version
7.2.34
Operating system
Linux
The text was updated successfully, but these errors were encountered:
Why you're using JsonSerializer? It is intended to be used for serializing simple jobs, and serializing ActiveRecord is way beyond "simple".
I'm not syncing the whole active record. Of course this would not be optimal. I use the queue to log a history of the changes of attributes. I only want to save a json field in the db with the changed attributes. And I have a column which is a datetime field, and I got this error, so I decided to report it.
I could use the PHP serializer, but JSON is better, because it is reusable with other languages and storage engines.
What steps will reproduce the problem?
Try to serialize an active record which has a datetime column with its default value
What's expected?
Serialize the object and then successfully unserializing it.
What do you get instead?
When you try to unserialize, you get an error because yii\db\Expression is missing required parameters in the constructor
Additional info
I have an idea to use reflection to get around the issue. Of course it will only work if the parameters are public properties. I will post here if it works.
The text was updated successfully, but these errors were encountered: