{"id":1085,"date":"2025-05-15T13:18:47","date_gmt":"2025-05-15T13:18:47","guid":{"rendered":"https:\/\/www.cmarix.com\/qanda\/?p=1085"},"modified":"2026-02-05T12:06:26","modified_gmt":"2026-02-05T12:06:26","slug":"laravel-custom-eloquent-casts-and-query-macros","status":"publish","type":"post","link":"https:\/\/www.cmarix.com\/qanda\/laravel-custom-eloquent-casts-and-query-macros\/","title":{"rendered":"How to Implement Custom Eloquent Casts or Query Macros in Laravel?"},"content":{"rendered":"\n<p>When building advanced Laravel applications, you often need to go beyond the default features. Two powerful tools for improving <strong>model behavior<\/strong> and <strong>query flexibility<\/strong> in Laravel are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Custom Eloquent Casts<\/strong> \u2013 for transforming how data is stored and retrieved on models<\/li>\n<\/ul>\n\n\n\n<p><strong>Query Macros<\/strong> \u2013 for extending the Eloquent query builder with reusable logic<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Are Custom Eloquent Casts?<\/h2>\n\n\n\n<p>They define how a model attribute should be <strong>transformed when accessed or saved<\/strong>. This is especially helpful for non-primitive types or custom logic.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Example: Custom Cast for JSON Settings<\/h3>\n\n\n\n<p>Let\u2019s say you store user settings as a JSON column in the database but want to work with it as an object.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1: Create a Custom Cast Class<\/h4>\n\n\n\n<p>bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>php artisan make:cast UserSettingsCast<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2: Implement the Cast Logic<\/h4>\n\n\n\n<p>PHP<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace App\\Casts;\nuse Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes;\nclass UserSettingsCast implements CastsAttributes\n{\n    public function get($model, string $key, $value, array $attributes)\n    {\n        return json_decode($value, true);\n    }\n    public function set($model, string $key, $value, array $attributes)\n    {\n        return json_encode($value);\n    }\n}\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3: Use the Cast in a Model<\/h4>\n\n\n\n<p>PHP<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class User extends Model\n{\n    protected $casts = &#91;\n        'settings' => \\App\\Casts\\UserSettingsCast::class,\n    ];\n}<\/code><\/pre>\n\n\n\n<p>Now, $user-&gt;settings will return an array instead of a raw JSON string, and setting it works the same way.<\/p>\n\n\n\n<p>PHP<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$user->settings = &#91;'dark_mode' => true, 'language' => 'en'];\n$user->save();\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">What Are Query Macros?<\/h2>\n\n\n\n<p>Query Macros allow <strong>Laravel developers<\/strong> to <strong>extend Laravel\u2019s query builder<\/strong> with custom methods, making your code <strong>DRY<\/strong> (Don&#8217;t Repeat Yourself) and easier to reuse across your app.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Example: Global Scope for Active Records<\/h3>\n\n\n\n<p>Let\u2019s say you frequently filter records that have a status = active.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1: Register a Macro<\/h4>\n\n\n\n<p>You can add this in a <strong>service provider<\/strong>, usually AppServiceProvider.<\/p>\n\n\n\n<p>PHP<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>use Illuminate\\Database\\Query\\Builder;\npublic function boot()\n{\n    Builder::macro('active', function () {\n        return $this->where('status', 'active');\n    });\n}\n<\/code><\/pre>\n\n\n\n<p>If you&#8217;re using Eloquent Builder (Illuminate\\Database\\Eloquent\\Builder), adjust accordingly.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2: Use the Macro in Queries<\/h4>\n\n\n\n<p>PHP<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$activeUsers = DB::table('users')->active()->get();<\/code><\/pre>\n\n\n\n<p>Or, if using Eloquent:<\/p>\n\n\n\n<p>PHP<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>use Illuminate\\Database\\Eloquent\\Builder;\nBuilder::macro('active', function () {\n    return $this->where('status', 'active');\n});\n<\/code><\/pre>\n\n\n\n<p>And then:<\/p>\n\n\n\n<p>PHP<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>User::query()->active()->get();<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">When to Use Casts vs. Macros<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Use Case<\/strong><\/td><td><strong>Use<\/strong><\/td><\/tr><tr><td>Transform model attributes<\/td><td>Custom Cast<\/td><\/tr><tr><td>Add reusable query logic<\/td><td>Query Macro<\/td><\/tr><tr><td>Reformat JSON, DateTime, objects<\/td><td>Custom Cast<\/td><\/tr><tr><td>Filter by status, scope, complex joins<\/td><td>Query Macro<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Best Practices<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Keep custom casts <strong>simple<\/strong> and <strong>pure<\/strong> \u2013 avoid side effects.<\/li>\n\n\n\n<li>Use <strong>descriptive macro names<\/strong> for readability <em>(->active(), ->filterByYear())<\/em>.<\/li>\n\n\n\n<li>Place macros in <strong>dedicated service providers<\/strong> for organization.<\/li>\n<\/ul>\n\n\n\n<p>Custom casts can also implement <em>CastsInboundAttributes<\/em> or Castable for even more flexibility.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When building advanced Laravel applications, you often need to go beyond the default features. Two powerful tools for improving model behavior and query flexibility in Laravel are: Query Macros \u2013 for extending the Eloquent query builder with reusable logic What Are Custom Eloquent Casts? They define how a model attribute should be transformed when accessed [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":1088,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[13,3],"tags":[],"class_list":["post-1085","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-laravel","category-web"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/1085","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/comments?post=1085"}],"version-history":[{"count":9,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/1085\/revisions"}],"predecessor-version":[{"id":1096,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/1085\/revisions\/1096"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media\/1088"}],"wp:attachment":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media?parent=1085"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/categories?post=1085"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/tags?post=1085"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}