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

Hash::remove() doesn't work if a child element is an object #17542

Closed
mehov opened this issue Jan 11, 2024 · 3 comments
Closed

Hash::remove() doesn't work if a child element is an object #17542

mehov opened this issue Jan 11, 2024 · 3 comments

Comments

@mehov
Copy link
Contributor

mehov commented Jan 11, 2024

Description

I fetch something from the database, pass it through Hash::combine() and I end up with an array of entities.

APP/Controller/ExampleController.php (line 123)
[
(int) 1 => object(MyPlugin\Model\Entity\User) id:0 { },
(int) 2 => object(MyPlugin\Model\Entity\User) id:11 { },
(int) 3 => object(MyPlugin\Model\Entity\User) id:18 { },
(int) 4 => object(MyPlugin\Model\Entity\User) id:25 { },
]

If I call Hash::remove() on it, nothing gets removed.

$result = Hash::remove(
    $users->toArray(), '{n}.email'
);

I looked through Hash::remove() source and I think this is due to the is_array($v) check here:

if ($match && is_array($v)) {

When I do debug(is_array($v)), I get false, and debug(\gettype($v)) outputs object.

So because the above is false, it continues to elseif where $nextPath === '' also evaluates to false since $nextPath is in this case 'email':

} elseif ($match && $nextPath === '') {

As a result, nothing happens.

Is this the intended behaviour?

The only way out of this, from the top of my head, is to loop through the input and force-convert every object to an array, but that negates the whole point of using the Hash shorthands, as I can remove what I need to remove in a loop in the first place, and as a bonus, avoid the (likely negligible) cost of parsing the string'{n}.email' at all.

CakePHP Version

5.0.2

PHP Version

8.3.1

@mehov mehov added the defect label Jan 11, 2024
@mehov mehov changed the title Hash::remove() doesn't work if a child element is not an array Hash::remove() doesn't work if a child element is an object Jan 11, 2024
@othercorey othercorey added this to the 4.5.3 milestone Jan 11, 2024
@markstory
Copy link
Member

I think expanding the feature set of Hash to handle objects that use a property based protocol is a good idea. The intention for Hash is to be a higher level query/map/reduce toolkit. I think operating on objects fits within those goals. By property based protocol, I'm thinking of a case like

} elseif (is_object($v) && isset($v->$nextPath)) {
   unset($v->$nextPath);
}

I think that would cover your scenario and also cover working with object results from json_encode.

@ADmad
Copy link
Member

ADmad commented Jan 12, 2024

I think expanding the feature set of Hash to handle objects that use a property based protocol is a good idea

That would create inconsistency with other methods like get() and extract() which only support ArrayAccess. So IMO the only change needed here is to include instanceof ArrayAccess along with the is_array() check.

@markstory
Copy link
Member

That would create inconsistency with other methods like get() and extract() which only support ArrayAccess.

I agree. Expanding to support object properties would need to be done across all of Hash if we were going to expand one of the methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants