Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Table field doesn't work with objects #3642

Closed
MeerKatDev opened this issue Mar 31, 2021 · 12 comments
Closed

[Bug] Table field doesn't work with objects #3642

MeerKatDev opened this issue Mar 31, 2021 · 12 comments
Assignees
Labels

Comments

@MeerKatDev
Copy link

Bug report

In the docs it's written that table works with objects, which I would think it means that it works with json objects like { 'a':'a', 'b':'b', ...}, instead it seems to be not usable for that.

What I did

I tried to show a JSON object with the table field.

What I expected to happen

For the object fields to show on different rows, like for the array case

What happened

htmlspecialchars error

What I've already tried to fix it

I'm building a custom field that works with objects

Backpack, Laravel, PHP, DB version

When I run php artisan backpack:version the output is:

@pxpm
Copy link
Contributor

pxpm commented Apr 1, 2021

@MeerKatDev cast your json field to object or array using model casts ? Also checkout this PR: #3387

Let me know if it solves for you,
Pedro

@pxpm pxpm self-assigned this Apr 1, 2021
@MeerKatDev
Copy link
Author

I tried both, none works. they give errors either way. What string representation is expected for object ?

@pxpm
Copy link
Contributor

pxpm commented Apr 1, 2021

Can't you convert your json to array to display ? also try with true as a second parameter, that enforce the json_decode https://www.php.net/manual/en/function.json-decode.php to be a array. If you are passing data from some front end component use stringify https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

https://backpackforlaravel.com/docs/4.1/crud-fields#table-1 states if your work with JSON from database, cast to object or array in model. Maybe the JSON you store is not valid ?

This is what my table saves in database:

[
    {
        "desc": "sfdg",
        "name": "sdfg"
    },
    {
        "desc": "sfdg",
        "name": "sfdg"
    }
]

Best,
Pedro

@MeerKatDev
Copy link
Author

MeerKatDev commented Apr 1, 2021

I thought it was clear above, but I will write it more explicitly: this is the json object I'm using:

{  "prop1": "val1", "prop2":"val2", ... }

which is a proper json object. This what you describe

[
    {
        "desc": "sfdg",
        "name": "sdfg"
    },
    {
        "desc": "sfdg",
        "name": "sfdg"
    }
]

is an array of json objects, and it's obviously not what I have an issue with. In the field table, Arrays work, objects don't. But in the docs that you linked, both object and array are described as compatible with the field. This is what I'm trying to describe in this bug report. Is that clear?

@pxpm
Copy link
Contributor

pxpm commented Apr 1, 2021

Hello @MeerKatDev I just tried casting to object:

public $casts = [
        'features'       => 'object',`
];

And it works as expected, What I am missing ?

Best,
Pedro

@MeerKatDev
Copy link
Author

MeerKatDev commented Apr 1, 2021

Could you show me what kind of data features is?

@pxpm
Copy link
Contributor

pxpm commented Apr 1, 2021

 CRUD::addField([ // Table
            'name'            => 'features',
            'label'           => 'Features',
            'type'            => 'table',
            'entity_singular' => 'feature', // used on the "Add X" button
            'columns'         => [
                'name' => 'Feature',
                'desc' => 'Value',
            ],
            'max' => 25, // maximum rows allowed in the table
            'min' => 0, // minimum rows allowed in the table
            'tab' => 'Texts',
        ]);

The saving of this table gives the string I showed you before when casted to object.

@MeerKatDev
Copy link
Author

Again, you are still describing an array of JSON objects here, not a JSON object. As the JSON specification says, the difference is:

JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

The casting that you are describing works because Laravel casts an array and an object in the same way, using json_encode, but they are not the same type of data . table supports only JSON arrays, not JSON objects.

So it's unclear to me why in the docs it says that it supports JSON in general. It doesn't. It supports only arrays.

@pxpm
Copy link
Contributor

pxpm commented Apr 1, 2021

Indeed you are right.

For reference here it what it says in docs:

It's highly recommended that you use attribute casting on your model when working with JSON stored in database columns, and cast your this attribute to either object or array.

It should be:

It's highly recommended that you use attribute casting on your model when working with JSON arrays stored in database columns, and cast your this attribute to either object or array.

I think there is room to improve here, this field is quite old, and at the time json columns where not widely used and a lot of DB versions didn't support it.

If you plan to work on this let us know, I think it would be a good addition to suport both json arrays and json objects directly from database.

@MeerKatDev
Copy link
Author

MeerKatDev commented Apr 1, 2021

I created a custom field that deals with any JSON object, should I make a PR? The issue is that it's a quick modification of the table field, and I removed a lot of js. There is a simple bpFieldInitTableObjectElement with a updateTableFieldJson implementation for objects, and nothing else.

@MeerKatDev
Copy link
Author

About the docs: I think it should be very clear that it deals only with array values. From

Show a table with multiple inputs per row and store the values as JSON in the database. The user can add more rows and reorder the rows as they please.

to

Show a table with multiple inputs per row and store the values as a JSON array of objects in the database. The user can add more rows and reorder the rows as they please.

and

It's highly recommended that you use attribute casting on your model when working with JSON arrays stored in database columns, and cast this attribute to array.

and I would leave object out :)

@pxpm
Copy link
Contributor

pxpm commented Apr 9, 2021

Thanks @MeerKatDev

I'v just submited: Laravel-Backpack/docs#247 to clear the docs a bit.

If you are willing to send a PR, please do it. If we can make table work with different types of data, or create a custom field, let's discuss there in the PR about the best approach.

I am going to close this for now.

Wish you the best,
Pedro

@pxpm pxpm closed this as completed Apr 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants