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

[5.4] Update Request::intersect to use array_intersect_key #15758

Closed
wants to merge 1 commit into from
Closed

[5.4] Update Request::intersect to use array_intersect_key #15758

wants to merge 1 commit into from

Conversation

RDelorier
Copy link
Contributor

This will prevent filtering null and falsy values when using Request intersect.

given

{
    "foo": " ",
    "bar": null,
    "baz": false
}

Before

Request::intersect('foo', 'bar', 'baz')
// ["foo" => " "]

After

Request::intersect('foo', 'bar', 'baz')
// ["foo" => " ",  "baz" => false]

moved from #15417

@GrahamCampbell
Copy link
Member

We already have a different method for that if you want null.

@RDelorier
Copy link
Contributor Author

Which method would that be?

@RDelorier
Copy link
Contributor Author

And what about false? If I post false then I would expect intersect to return that value

@wanghanlin
Copy link
Contributor

wanghanlin commented Oct 6, 2016

I think we need that function, but @RDelorier what about create a new function or add an option parameter to old function since @taylorotwell can't change the old one right now for the compatibility.
@GrahamCampbell please see #15417, we need a function or add a parameter that only filter out those null value added by only function, without removing all those false value submitted from a form.

@RDelorier
Copy link
Contributor Author

I've been shut down twice with this so I'm gonna let it be, I'll just continue to use my macros for now.

@wanghanlin
Copy link
Contributor

@RDelorier do you mind to share your macros here? I think it's helpful for others whoever face this same situation.

@taylorotwell taylorotwell reopened this Oct 6, 2016
@taylorotwell
Copy link
Member

@GrahamCampbell can you answer the question about what method they are supposed to use.

@RDelorier
Copy link
Contributor Author

@shwhl here is the macro I'm currently using for this

// in my AppServiceProvider
\Request::macro('intersectKeys', function ($keys) {
    return array_intersect_key($this->all(), array_flip($keys));
});

And I use it instead of intersect

Route::post('/test', function (Illuminate\Http\Request $request) {
    dd([
        'intersect' => $request->intersect(['a', 'b', 'c', 'd']), 
        'intersectKeys' => $request->intersectKeys(['a', 'b', 'c', 'd'])
    ]);
});

Then when I post this

{
    "a": null,
    "b": "",
    "c": false,
    "d": "foo",
    "e": "bar"
}

I get this result

array:2 [
  "intersect" => array:1 [
    "d" => "foo"
  ]
  "intersectKeys" => array:4 [
    "a" => null
    "b" => ""
    "c" => false
    "d" => "foo"
  ]
]

@wanghanlin
Copy link
Contributor

@RDelorier thank you! that's really helpful, I forget we can add macros, I was thinking to create a package for this before.

@taylorotwell
Copy link
Member

What is the difference between this and $request->only()?

@taylorotwell
Copy link
Member

After a quick unit test it seems that ->only does what you want.

@wanghanlin
Copy link
Contributor

wanghanlin commented Oct 10, 2016

@taylorotwell if $request = ['foo' => 'bar']; $request->only('foo', 'baz'); will cause the final array ['foo'=>'bar', 'baz'=>null], the intersect function will remove baz since its value is null. That's how current intersect works. but the intersect function will also remove those key with a false value.
like $request=['foo'=>'bar', 'baz'=>false], after $request->intersect('foo','baz') it will be ['foo'=>'bar']. The function @RDelorier wrote will keep the false value, but also remove null value(which added by only function if user passes some keys not existed in $request)

@RDelorier
Copy link
Contributor Author

Like @shwhl said, request only will return every key you pass and will fill in with null if they are not in the request which would cause you unintentionally nullify fields that were not passed in. Intersect would only include null if the request received the field and it was null.

@RDelorier
Copy link
Contributor Author

@taylorotwell here is another example to show the difference in $request->only

Request::macro('intersectKeys', function ($keys) {
    return array_intersect_key($this->all(), array_flip($keys));
});

$request = Request::create('/', 'GET', [
    'a' => 'foo',
    'b' => null,
    'c' => false,
]);

dd([
    'only' => $request->only(['a', 'b', 'c', 'd']),
    'intersect' => $request->intersect(['a', 'b', 'c', 'd']),
    'intersectKeys' => $request->intersectKeys(['a', 'b', 'c', 'd'])
]);

result:

array:3 [
  "only" => array:4 [
    "a" => "foo"
    "b" => null
    "c" => false
    "d" => null  <-- defaulted to null event tho not in request data
  ]
  "intersect" => array:1 [
    "a" => "foo"
  ]
  "intersectKeys" => array:3 [
    "a" => "foo"
    "b" => null
    "c" => false
  ]
]

@amochohan
Copy link
Contributor

amochohan commented Mar 24, 2017

I've also stumbled into this issue today. My particular use case is to implement a patch request.

Take the following example, to partially update a user's details:

$this->json('patch', '/api/v1/user/1', [
    'email' => 'amo@domain.com',
    'is_active' => false
]

// In my controller:

$user->update($request->intersect(['email', 'name', 'is_active']));

In this example, the email will be updated - but not the is_active attribute, because I've provided a false value.

@JosephSilber
Copy link
Member

JosephSilber commented Mar 24, 2017

Related: #17842 (comment)

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

Successfully merging this pull request may close these issues.

6 participants