-
Notifications
You must be signed in to change notification settings - Fork 916
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] Repeatable subfields not getting the correct old() value if there's a field with the same name in the main form #4029
Conversation
The inspection completed: 544 Issues, 80 Patches |
Hello. Thank you for quick response. OriginCrudController.php My
|
You need to define: |
I just created another fresh Crud controller so I could easily share it here and used different model just to make sure. That's why withPivot() was missing. (forgot to add it)
I can confirm that it doesn't work either way. |
$current_value = array($current_value[$field['row_key']][$field['name']]); | ||
} | ||
} | ||
|
||
$current_value = $connected_entity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pxpm
Keep in mind that I have no idea about backpack source code so I might be completly wrong.
You expect here $current_value to be an array of ids.
I logged it and that's what I got.
Sometimes its just array of ids, sometimes its array of arrays.
Why? I don't know.
[2021-12-22 22:07:41] local.DEBUG: array (
0 => '1',
)
[2021-12-22 22:07:41] local.DEBUG: array (
0 => '2',
)
[2021-12-22 22:07:41] local.DEBUG: array (
0 =>
array (
'characters' => '1',
'as' => 'noooo',
),
1 =>
array (
'characters' => '2',
'as' => NULL,
),
)
So obviously, ->whereIn($connected_entity_key_name, $current_value)
will throw an error. Because $current_value is not array of ids but multidimensional array.
I made changes to relationship_select.blade.php in order to make it work.
Don't take this code too seriously.
case 'array':
// check if field have `row_key` set, if it has we are in a repeatable
// and should get the current row value
if(isset($field['row_key'])) {
if (isset($current_value[$field['row_key']]) && isset($current_value[$field['row_key']][$field['name']])) {
$current_value = array($current_value[$field['row_key']][$field['name']]);
}
}
/// Check if array is multidimensional.
if (count($current_value) == count($current_value, COUNT_RECURSIVE))
{
/// Do as usual. Array contains only ids.
$current_value = $connected_entity
->whereIn($connected_entity_key_name, $current_value)
->get()
->pluck($field['attribute'], $connected_entity_key_name);
}
else
{
/// We Have to loop throught array because its array of arrays.
/// Then get $field['name'] from array and create array of ids.
$arr = array();
foreach ($current_value as $key => $value) {
array_push($arr, $value[$field['name']]);
}
$current_value = $connected_entity
->whereIn($connected_entity_key_name, $arr)
->get()
->pluck($field['attribute'], $connected_entity_key_name);
}
break;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @PitchRE 🙏
@pxpm I tried it, I replicated the bug, but... I'm still not sure I understand your solution, it seems overly complicated to me... And I have to admit, as soon as I heard "we have to change all the fields to account for this key"... Help me out, here's how I rephrase it in my own words...
And you're saying that's because the input names are identical for BOTH the main relationship AND the primary key of each entry: Which makes sense. But here's what I don't understand: when Laravel loads the blade file for the first select2 in that repeatable... isn't it trying to get the old value of
If that's the problem, I agree with you, the solution wouldn't be this one. And it definitely wouldn't be to modify all our fields to account for the repeatable row key. The solution would be to get What do you think @pxpm ? Am I understanding this correct? Is this the path forward? |
belongsToMany
relation
@tabacitu you are totally right in your reasoning. Just don't focus too much on is a BUT unfortunatelly we have no way to know what is the field name before the field is completely setup.
array:19 [▼
"name" => "dummyproducts"
"multiple" => false
"ajax" => false
"data_source" => "false"
"minimum_input_length" => 0
"delay" => 500
"placeholder" => "Select an entry"
"entity" => "dummyproducts"
"label" => "Dummyproducts"
"relation_type" => "BelongsToMany"
"model" => "App\Models\Product"
"attribute" => "name"
"pivot" => true
"type" => "relationship_select"
"row_key" => 0
"value" => "1"
"allows_null" => true
"include_all_form_fields" => true
"options" => Illuminate\Support\Collection {#1974 ▶}
]
It will fail in scenarios where you have a field with same name inside repeatable and outside repeatable, because We cannot simply check if it is an array because there are fields that really post an array. So the way I found to distinguish when we should intervene is setting up I also think this should be done inside the Let me know if you think of other way to deal with this. Pedro |
My question is... why does repeatable not change the subfield names in PHP instead of JS? It knows the fields. Why does repeatable not use that information to make sure the subfields use "testimonial[name]" instead of "name". Isn't that possible and/or recommended? |
If repeatable made sure the names are correct (nested with dot or array syntax whatever), then the old value would be populated correctly with the function I just posted in an inline comment in the oldValeDefaultOrFallback() PR. |
@tabacitu because some fields change their name in the field itself, like We can do a BC in this field and instead of accepting array names we accept only single field name, and add a config in the field to determine to what columns the values should be saved, by default I think it's the only field that accepts an array as field name. I think if it is not because that field, we can change the names on display. I will have to have a better look also in fields that uses hidden inputs but I think there is no problem there. Want me to put up a PR with this solution ? |
Just created a PR for it: #4032 Does not cover fields that accept Should work well for majority of fields. Didn't tested 1 by 1. If that PR gets accepted this should be closed. |
belongsToMany
relation
I don't see why this wouldn't work for arrays too... please see https://github.com/Laravel-Backpack/CRUD/pull/4032/files#r774663397 |
WHY
BEFORE - What was wrong? What was happening before this PR?
As reported in #4027 there seemd to be something wrong with repeatable and old values.
While testing I found out the culprit of this was the fact that
old($field_name)
returns true in case ofM-M
relationships because the repeatable name itself, it's the name of the pivot field.In
M-M
relationships, or in case your repeatable name have the same name as some field inside the repeatable when that field gets it'sold()
value from session, it will get the FULL repeatable value and not that specific row value.AFTER - What is happening after this PR?
After the PR if the returned from old is not what we expect (a single field value, but the whole repeatable value) we will parse it accordingly.
HOW
How did you achieve that, in technical terms?
Introduced
row_key
that are passed throughrepeatable_relation
reaching the field. When setting up field value, we check if that row_key is set, if it is, we parse the value accordingly.Is it a breaking change or non-breaking change?
4.2
How can we test the before & after?
Add a belongstomany relation, create 2 or 3 entries. Update the entry making the validation fail and see that ALL the pivots have the same entry selected.
BEFORE UPDATE:

ON UPDATE WITH VALIDATION ERRORS:

@tabacitu 2 things that I think that are worth talking about:
row_key
parameter for repeatable and parse the value there. This would make the fix work for ANY field used inside the repeatable, because the principle it's the same.Let me know what you think,
Pedro