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

select2_json_from_api wrong attribute to store behaviour #5517

Closed
miquelangeld opened this issue May 7, 2024 · 7 comments
Closed

select2_json_from_api wrong attribute to store behaviour #5517

miquelangeld opened this issue May 7, 2024 · 7 comments
Assignees
Labels
question Further information is requested

Comments

@miquelangeld
Copy link

Bug report

What I did

I implemented the field like this:

$this->crud->addField([
            'label' => 'Booking', 
            'type' => 'select2_json_from_api',
            'name' => 'booking', 
            'data_source' => url('/admin/bookings/ajax-bookings-avalon-options'),
            'attribute' => 'id', 
            'attributes_to_store' => ['id'],
            'placeholder' =>'Select booking',
        ]);

the data source endpoint return this:
[
{
"id":"MURR230044076-1",
"booking":"MURR230044076-1 Localizador: MUR0002611"
}
]

So I expect that the value stored should be MURR230044076-1
but is storing this: {"id":"MURR230044076-1"} instead

Also if in the field I use different attributes:
'attribute' => 'booking',
'attributes_to_store' => ['id'],

then the select doesn't show any option

@karandatwani92
Copy link
Contributor

Hey @miquelangeld

select2_json_from_api is primarily designed for external APIs.

Your API source looks internal, so I recommend you use select2_from_ajax with Fetch Operation for the desired value.

@miquelangeld
Copy link
Author

miquelangeld commented May 7, 2024

Hi @karandatwani92 although the url is internal, the data actually comes from an external system. But I have a class to query this data. I can't use select2_from_ajax, look this issue
anyway if the endpoint return an object with the attribute id the stored value should be MURR230044076-1 not the json {"id":"MURR230044076-1"} isn't?

@karandatwani92
Copy link
Contributor

karandatwani92 commented May 7, 2024

OK, I'm asking my colleague to guide here; he is the creator of this field. @promatik please help!

@karandatwani92 karandatwani92 added question Further information is requested and removed triage labels May 7, 2024
@miquelangeld
Copy link
Author

Any chance to resolve this?

@pxpm
Copy link
Contributor

pxpm commented May 16, 2024

Hello @miquelangeld sorry for the delay, this one is on me 🙏

The "main" purpose behind creating this field, was to consume external API's, so the main need is to store "at least" the id + any additional attributes you setup.

We discussed the possibility to support storing non-json in database, but that would deviate the field from the main purpose, plus it would only fit some use cases.
Most likely you want to store an id, and show other attribute, not in your scenario, but if you think how most selects works, it display some user friendly string, while storing "machine strings/ids".

If we don't store both as json, when "editing" the entry, we would have only "the key", not the display value.

[
   'pending-review' => 'Pending Review',
   'isbn-001-az4' => 'Harry Potter Book 1', 
]

Your usecase is achievable with some extra step. You need to "trick" the field value, basically inverting what the field does.
You decode the field json value before saving in the database, and store only the string you want.
When you retrieve the entry from the database you encode the string in a format that the field is expecting.

CRUD::field('my_field') // ....
         ->events([
                   'saving' => function($entry) {
                         $entry->booking = json_decode($entry->booking?? [], true)['id'] ?? null;
                    },
                    'retrieved' => function($entry) {
                         $entry->booking = json_encode(['id' => $entry->booking]);
                    }
         ])

Doing this as model events only registered on the fields has the advantage over accessors/mutators because they will only happen when on a "crud context" where fields are used. When you retrieve your model with Model::find(id) you will still have a string when doing $model->booking vs if you did this as accessors/mutators you would get json from $model->booking.

Please note that while testing this solution (because I was not happy with the accessor messing with my model in general just to handle a field type), I found a bug with Backpack that I already fixed in 6.7.13, so please do a composer update backpack/crud before using this solution.

Let me know if that helps.

Cheers

@miquelangeld
Copy link
Author

Hi @pxpm you're totally right and make perfect sense. It's a little bit embarrasing, but I didn't pay enough attention to the docs and the fact that the field store json by definition (I know it's even in the name select2_JSON_from_api) I close the issue. The field works perfectly. I've been waiting for this feature!! Thanks!! I also will close this one

@pxpm
Copy link
Contributor

pxpm commented May 17, 2024

Hi @pxpm you're totally right and make perfect sense. It's a little bit embarrasing, but I didn't pay enough attention to the docs and the fact that the field store json by definition (I know it's even in the name select2_JSON_from_api) I close the issue. The field works perfectly. I've been waiting for this feature!! Thanks!! I also will close this one

Thank you @miquelangeld, I wouldn't be embarrassed, you pursued a valid use case I guess. It ended up with a bug fix, a docs update and your need satisfied. I would say it was win-win 👍

Thanks for your time and patience 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
Status: Done
Development

No branches or pull requests

4 participants