<?php
namespace App\Providers;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Collection macro
Collection::macro('toSelectArray', function () {
return $this->mapWithKeys(function ($item) {
return [$item->id => $item->name];
});
});
// String macro
Str::macro('partNumber', function ($value) {
return 'PART-' . strtoupper(Str::slug($value));
});
// Query Builder macro
Builder::macro('whereLike', function ($column, $value) {
return $this->where($column, 'like', "%{$value}%");
});
// Request macro
Request::macro('hasAny', function (...$keys) {
foreach ($keys as $key) {
if ($this->has($key)) {
return true;
}
}
return false;
});
// Response macro
Response::macro('success', function ($data = [], $message = 'Success') {
return response()->json([
'success' => true,
'message' => $message,
'data' => $data,
]);
});
}
}
<?php
use Illuminate\Support\Str;
// Collection macro
$users = User::all();
$options = $users->toSelectArray();
// ['1' => 'John', '2' => 'Jane', ...]
// String macro
$partNumber = Str::partNumber('widget-2000');
// "PART-WIDGET-2000"
// Query Builder macro
$posts = Post::whereLike('title', 'laravel')->get();
// Request macro
if (request()->hasAny('name', 'email', 'phone')) {
// At least one field provided
}
// Response macro
return response()->success($posts, 'Posts retrieved');
<?php
namespace App\Mixins;
class CollectionMixins
{
public function toSelectArray()
{
return function () {
return $this->mapWithKeys(fn ($item) => [$item->id => $item->name]);
};
}
public function paginate()
{
return function ($perPage = 15) {
$page = request('page', 1);
return new \Illuminate\Pagination\LengthAwarePaginator(
$this->forPage($page, $perPage),
$this->count(),
$perPage,
$page
);
};
}
}
// Register mixin in service provider
Collection::mixin(new CollectionMixins());
Macros dynamically add methods to Laravel's macroable classes—Request, Response, Collection, Query Builder, and more. I define macros in service providers' boot() methods. The macro() method accepts a name and closure. Macros access $this context like regular methods. Mixin provides multiple macros at once from a class. I use macros for project-specific helpers without extending classes. String, Arr, and Collection macros create domain-specific utilities. Request macros add custom validation or data extraction. This extensibility keeps framework modifications organized and upgradeable. Macros demonstrate Laravel's flexibility for customization.