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

[11.x] Allow callback to be passed to updateOrInsert() to pass different $values if the record already exists #51566

Merged
merged 3 commits into from
May 30, 2024

Conversation

Markshall
Copy link
Contributor

@Markshall Markshall commented May 24, 2024

Earlier today I found myself wanting to pass a different array of values to updateOrInsert() depending on whether the record already existed or not. Effectively, I only wanted to update a specific column on the initial insertion of a record, not any future updates of said record.

To do this, I defined an array with values I definitely want to update, then did a conditional check to see if the record exists to add more elements to the array, like so:

$values = [
  'name' => $data['name'],
  'email' => $data['email'],
];

$exists = DB::table('users')->where('user_id', $user_id)->exists();

if (! $exists) {
  $values['optional_column'] = $data['foobar'];
}

DB::table('users')->updateOrInsert(
  ['user_id' => $user_id],
  $values
);

updateOrInsert() already internally performs the check for existence, so the check was being executed twice.

This PR allows a callback to be passed that will return an array, instead of just passing an array with conditional keys (see example below).
An array is still able to be passed through, and is still set as the default parameter, for backwards compatibility.

DB::table('users')->updateOrInsert(
  ['user_id' => $user_id],
  function ($exists) use ($data) {
    if ($exists) {
      return [
        'name' => $data['name'],
        'email' => $data['email'],
      ];
    }

    return [
      'name' => $data['name'],
      'email' => $data['email'],
      'optional_column' => $data['foobar'],
    ];
  }
);

Of course, you could still do the conditional keys, but keep it contained within the callback for tidiness.

DB::table('users')->updateOrInsert(
  ['user_id' => $user_id],
  function ($exists) use ($data) {
    $values = [
      'name' => $data['name'],
      'email' => $data['email'],
    ];

    if (! $exists) {
      $values['optional_column'] = $data['foobar'];
    }

    return $values;
  }
);

* @return bool
*/
public function updateOrInsert(array $attributes, array $values = [])
public function updateOrInsert(array $attributes, $values = [])
Copy link

@jeanmarinho529 jeanmarinho529 May 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can keep the parameter typing in this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can keep the parameter typing in this function.

Although the function itself will return an array, the argument being passed will still be a function so it will throw a TypeError based on that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a union type, then?

public function updateOrInsert(array $attributes, callable|array $values = [])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a union type, then?

public function updateOrInsert(array $attributes, callable|array $values = [])

Definitely. I'll amend my PR to update it.

I'm currently working in an old project running on PHP 7.4, so am unable to use union types. I just made the amends locally and then made the PR with what worked for me in that setup without accounting for the PHP 8 support in Laravel 11.

@taylorotwell taylorotwell merged commit 92eda54 into laravel:11.x May 30, 2024
28 checks passed
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.

4 participants