Back to Course |
Design Patterns in Laravel 11

Builder: in View, Validation, Relationships

So, we move into the world of patterns inside the framework itself, starting with Builder.

Of course, the Builder pattern can be seen in more places than just your code - for example, in the /vendor folder!


Builder in View

Take a look at this code.

Some Controller

return view('greeting')
->with('name', 'Victoria')
->with('occupation', 'Astronaut');

It's a typical Laravel view usage, but if we look closer, it's a Builder pattern!

Especially if we take a look at the source code of the ->with() method, we can see that it returns $this:

Illuminate/View/View.php

public function with($key, $value = null)
{
if (is_array($key)) {
$this->data = array_merge($this->data, $key);
} else {
$this->data[$key] = $value;
}
 
return $this;
}

In this case, the Builder pattern is one of many patterns used in Laravel to make things easier for developers.


Builder in Validation Rules

Another example of a Builder pattern in Laravel is the validation system. Let's look at the dimensions rule:

Some Controller

Validator::make($data, [
'avatar' => [
'required',
Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
],
]);

In this case, we can see that we were able to chain multiple methods to the dimensions rule. This is possible because the dimensions rule returns $this:

Illuminate/Validation/Rules/Dimensions.php

public function maxWidth($value)
{
$this->constraints['max_width'] = $value;
 
return $this;
}
 
/**
* Set the "max height" constraint.
*
* @param int $value
* @return $this
*/
public function maxHeight($value)
{
$this->constraints['max_height'] = $value;
 
return $this;
}
 
/**
* Set the "ratio" constraint.
*
* @param float $value
* @return $this
*/
public function ratio($value)
{
$this->constraints['ratio'] = $value;
 
return $this;
}

Essentially, the Builder pattern allows us to chain multiple methods to a single object. This opens up many customization possibilities and makes the code more readable.

This is repeated for quite a few rules in Laravel, like:


Builder in Eloquent Relationships

The last example is a bit more advanced as it works in specific scenarios on the Relationships:

app/Models/User.php:

return $this->belongsToMany(Role::class)
->withPivot('active', 'created_by')
->withTimestamps();

We can see chained methods on the belongsToMany relationship in this case. This is due to some "Laravel magic," but it's essentially the Builder pattern in action.

Let's look at the withPivot method:

Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php:

public function withPivot($columns)
{
$this->pivotColumns = array_merge(
$this->pivotColumns, is_array($columns) ? $columns : func_get_args()
);
 
return $this;
}

As you can see, it returns $this, which allows us to chain more methods to the relationship. The same goes for the withTimestamps method:

Illuminate/Database/Eloquent/Relations/BelongsToMany.php

public function withTimestamps($createdAt = null, $updatedAt = null)
{
$this->withTimestamps = true;
 
$this->pivotCreatedAt = $createdAt;
$this->pivotUpdatedAt = $updatedAt;
 
return $this->withPivot($this->createdAt(), $this->updatedAt());
}

In this case, it is also called the withPivot() method, which allows us to chain more methods.


Laravel Core is full of examples like this. They might be deeply integrated or hidden behind some "magic", but they are there. And they depend on the Builder pattern to work.