Translate-plugin: attributesToArray does not work with translated jsonable attributes

Created on 21 May 2019  路  7Comments  路  Source: rainlab/translate-plugin

I've got a model:

class Product extends Model {
    public $jsonable = ['links'];
    public $translatable = ['links'];
    public $implement = ['@RainLab.Translate.Behaviors.TranslatableModel'];
}

When I do this...

$p = Product::first();
$p->attributesToArray();

... everything works as expected. When I run...

$p = Product::first();
$p->lang('fr')->attributesToArray();

... i get:

PHP Warning:  json_decode() expects parameter 1 to be string, array given in /(...)/vendor/october/rain/src/Database/Model.php on line 1115

It seems like the jsonable attributes are already turned into an array when loaded via the trans method. The subsequent call to json_decode in Model.php therefore fails.

https://github.com/octobercms/library/blob/master/src/Database/Model.php#L1115

Completed Bug

Most helpful comment

This line seems to be the problem:
https://github.com/rainlab/translate-plugin/blob/master/classes/TranslatableBehavior.php#L165

Without it the attributesToArray() call works but obviously everything else is broken.

The simplest solution that comes to mind is to add a is_array check to the attributesToArray method:

        foreach ($this->jsonable as $key) {
            if (
                !array_key_exists($key, $attributes) ||
                in_array($key, $mutatedAttributes)
            ) {
                continue;
            }

            // Prevent double decoding
            if (is_array($attributes[$key])) {
                continue;
            }

            $jsonValue = json_decode($attributes[$key], true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $attributes[$key] = $jsonValue;
            }
        }

All 7 comments

Hmm, this is caused by loadTranslatableData() in behaviors/TranslatableModel.php, It's decoding the values before returning it.

Try commenting out the json_decode() call in there just to see if that fixes the problem.

I'm sure this code is needed, so we'll need to investigate deeper.

Maybe we should use a try/catch block in library/src/Database/Model.php, I am not sure how to prevent this double decoding.

This line seems to be the problem:
https://github.com/rainlab/translate-plugin/blob/master/classes/TranslatableBehavior.php#L165

Without it the attributesToArray() call works but obviously everything else is broken.

The simplest solution that comes to mind is to add a is_array check to the attributesToArray method:

        foreach ($this->jsonable as $key) {
            if (
                !array_key_exists($key, $attributes) ||
                in_array($key, $mutatedAttributes)
            ) {
                continue;
            }

            // Prevent double decoding
            if (is_array($attributes[$key])) {
                continue;
            }

            $jsonValue = json_decode($attributes[$key], true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $attributes[$key] = $jsonValue;
            }
        }

Yes, that would make the most sense.

Can you submit a PR for this @tobias-kuendig ?

@tobias-kuendig make it a !is_string check instead please

Was this page helpful?
0 / 5 - 0 ratings