Skip to content

[12.x] Add flag to disable where clauses for withAttributes method on Eloquent Builder #55199

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

Merged

Conversation

AndrewMast
Copy link
Contributor

@AndrewMast AndrewMast commented Mar 28, 2025

Why

The withAttributes method (documented here) is very helpful for adding attributes to both the where clauses as well as the attributes when a model is made from the relationship.

However, I ran into a situation where I needed to set an attribute when the relationship is created, but not constrain the relationship to only rows where the attribute is set to that value.

The $pendingAttributes property already exists on the Eloquent builder and all the logic to add the pending attributes to the new models also exist.

What

A new argument ($asConditions, defaults to true) was added withAttributes method on the Eloquent builder to determine whether the attributes passed into the method will also create where clauses.

Implementation:

/**
 * Specify attributes that should be added to any new models created by this builder.
 *
 * The given key / value pairs will also be added as where conditions to the query.
 *
 * @param  \Illuminate\Contracts\Database\Query\Expression|array|string  $attributes
 * @param  mixed  $value
 * @param  bool  $asConditions
 * @return $this
 */
public function withAttributes(Expression|array|string $attributes, $value = null, $asConditions = true)
{
    if (! is_array($attributes)) {
        $attributes = [$attributes => $value];
    }

    if ($asConditions) {
        foreach ($attributes as $column => $value) {
            $this->where($this->qualifyColumn($column), $value);
        }
    }

    $this->pendingAttributes = array_merge($this->pendingAttributes, $attributes);

    return $this;
}

Usage:

/**
 * Get the students that the teacher has.
 */
public function students(): HasMany {
    return $this->hasMany(Student::class)->withAttributes('current_teacher_id', $this->id, asConditions: false);
}
See previous PR content

Why

Another attempt at #55178. Instead of adding the pendingAttributes method, Taylor said he would rather have this passed as a named argument to withAttributes (see comment).


The withAttributes method (documented here) is very helpful for adding attributes to both the where clauses as well as the attributes when a model is made from the relationship.

However, I ran into a situation where I needed to set an attribute when the relationship is created, but not constrain the relationship to only rows where the attribute is set to that value.

The $pendingAttributes property already exists on the Eloquent builder and all the logic to add the pending attributes to the new models also exist.

What

This led to me creating the pendingAttributes method to do the same thing as withAttributes but not touch the where clauses.

This led to me adding the pending named argument to the withAttributes method on the Eloquent builder.

I added an $addWheres flag (probably should be renamed) to the withAttributes method on the Eloquent builder to determine whether the attributes passed into the method will also create where clauses. The default value is true.

Tests:

  • tests/Database/DatabaseEloquentBelongsToManyWithAttributesPendingTest.php
    Copied from DatabaseEloquentBelongsToManyWithAttributesTest.php and made sure only the relational where clauses exist
  • tests/Database/DatabaseEloquentHasOneOrManyWithAttributesPendingTest.php
    Copied from DatabaseEloquentHasOneOrManyWithAttributesTest.php and made sure only the relational where clauses exist
  • tests/Database/DatabaseEloquentWithAttributesPendingTest.php
    Copied from DatabaseEloquentWithAttributesTest.php and made sure no where clauses exist

Alternative

Edit: Implemented the alternative! Current interface is withAttributes(Expression|array|string $attributes, $value = null, $addWheres = true)

One downside to using a named parameter to pass the pending attributes, is that the $attributes argument is still required, meaning we would need to do ->withAttributes([], pending: ['key' => 'value']) to use it. After creating this commit, I had the idea that we could simply add a $applyWhere or $addWhere to withAttributes to dictate whether the where clauses are added (true by default)

Taylor, if you like the idea of changing withAttributes to withAttributes(Expression|array|string $attributes, $value = null, $addWheres = true) over withAttributes(Expression|array|string $attributes, $value = null, array $pending = []), please let me know before closing the PR and I will update it.

@taylorotwell
Copy link
Member

@AndrewMast my preference to have a boolean flag as you note in your alternatives. I'm not sure what the variable name but if you give it a shot I can always rename it later in review. Please mark as ready for review when the requested changes have been made. 👍

@taylorotwell taylorotwell marked this pull request as draft March 29, 2025 16:59
@AndrewMast AndrewMast marked this pull request as ready for review March 29, 2025 17:01
@AndrewMast
Copy link
Contributor Author

@taylorotwell Ready! I had the commit waiting to push. Only pinging since you commented a few minutes ago.

@AndrewMast AndrewMast changed the title [12.x] Add additional argument to Eloquent Builder withAttributes method [12.x] Add flag to disable where clauses for withAttributes method on Eloquent Builder Mar 29, 2025
@taylorotwell taylorotwell merged commit 4b9c9a4 into laravel:12.x Mar 29, 2025
39 checks passed
@AndrewMast
Copy link
Contributor Author

asConditions is much better! Thanks for the merge.

@AndrewMast AndrewMast deleted the feat/builder-with-pending-attributes branch March 29, 2025 17:19
@AndrewMast AndrewMast restored the feat/builder-with-pending-attributes branch March 29, 2025 17:30
@AndrewMast AndrewMast deleted the feat/builder-with-pending-attributes branch March 29, 2025 17:32
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.

None yet

2 participants