<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Anders Iglebekk on Medium]]></title>
        <description><![CDATA[Stories by Anders Iglebekk on Medium]]></description>
        <link>https://medium.com/@anders.iglebekk?source=rss-c92c2a799c42------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*aweAJyx_kDYF8Lu4</url>
            <title>Stories by Anders Iglebekk on Medium</title>
            <link>https://medium.com/@anders.iglebekk?source=rss-c92c2a799c42------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 00:21:12 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@anders.iglebekk/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Efficient Metadata Filtering in Laravel 10.x: A No-Package Approach]]></title>
            <link>https://medium.com/@anders.iglebekk/efficient-metadata-filtering-in-laravel-10-x-a-no-package-approach-718b5cea0daa?source=rss-c92c2a799c42------2</link>
            <guid isPermaLink="false">https://medium.com/p/718b5cea0daa</guid>
            <category><![CDATA[php]]></category>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[eloquent]]></category>
            <dc:creator><![CDATA[Anders Iglebekk]]></dc:creator>
            <pubDate>Mon, 05 Feb 2024 12:25:55 GMT</pubDate>
            <atom:updated>2024-02-05T12:25:55.349Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RHbwboNDJOfLUVfSH2HCzg.png" /></figure><p>In the realm of web development, efficiently managing and querying metadata is a recurring challenge, especially when dealing with a diverse set of data across various clients. This article delves into creating a flexible and efficient metadata filter in Laravel 10.x, without the reliance on extra packages.</p><h3>The Scenario</h3><p>Consider an application structure where a Client has many Profiles, and each Profile has many ProfileRows, akin to:</p><pre>$ProfileRow = [<br>    &#39;name&#39; =&gt; &#39;Phone&#39;,<br>    &#39;content&#39; =&gt; &#39;+458988898&#39;,<br>];</pre><p>This simple yet flexible metadata structure caters well to varying client requirements. However, efficiently filtering through this metadata, based on different operators, names, and content of ProfileRows, posed a significant challenge.</p><h4>The Initial Request</h4><p>The base request looked something like this:</p><pre>$client_id = 1;<br>$client = Client::find($client_id);<br>$profiles = $client-&gt;profiles()-&gt;with(&#39;profile_rows&#39;)-&gt;get();</pre><h3>The Solution</h3><h4>Creating Enums for Operators</h4><p>A flexible set of operators is crucial for a robust filter. Enums in PHP (introduced in PHP 8.1) offer a type-safe way to define such sets. Here’s how you can define an Enum for your operators:</p><pre>namespace App\Enums;<br><br>enum FilterOperator: string {<br>    case Equals = &#39;equals&#39;;<br>    case Contains = &#39;contains&#39;;<br>    case GreaterThan = &#39;greater_than&#39;;<br>    case LessThan = &#39;less_than&#39;;<br>    case GreaterThanOrEqual = &#39;greater_than_or_equal&#39;;<br>    case LessThanOrEqual = &#39;less_than_or_equal&#39;;<br>}</pre><h4>Setting up a Scope in the Model</h4><p>Laravel’s eloquent scopes are a powerful feature that allows you to encapsulate common query logic. By adding a scope to the Profile model, you can streamline the filtering process:</p><pre>namespace App\Models;<br><br>use App\Enums\FilterOperator;<br>use Illuminate\Database\Eloquent\Model;<br><br>class Profile extends Model {<br>    public function scopeWithProfileRowsFilters($query, array $filters) {<br>        foreach ($filters as $filter) {<br>            if (!isset($filter[&#39;name&#39;]) || !isset($filter[&#39;operator&#39;]) || !isset($filter[&#39;content&#39;])) {<br>                throw new \InvalidArgumentException(&#39;Invalid filter&#39;);<br>            }<br>            $operator = FilterOperator::tryFrom($filter[&#39;operator&#39;]);<br>            if (!$operator) {<br>                throw new \InvalidArgumentException(&#39;Invalid operator&#39;);<br>            }<br>            $query-&gt;whereHas(&#39;profile_rows&#39;, function ($query) use ($filter, $operator) {<br>                $query-&gt;where(&#39;name&#39;, $filter[&#39;name&#39;]);<br>                match ($operator) {<br>                    FilterOperator::Equals =&gt; $query-&gt;where(&#39;content&#39;, $filter[&#39;content&#39;]),<br>                    FilterOperator::Contains =&gt; $query-&gt;where(&#39;content&#39;, &#39;like&#39;, &#39;%&#39; . $filter[&#39;content&#39;] . &#39;%&#39;),<br>                    FilterOperator::GreaterThan =&gt; $query-&gt;where(&#39;content&#39;, &#39;&gt;&#39;, $filter[&#39;content&#39;]),<br>                    FilterOperator::LessThan =&gt; $query-&gt;where(&#39;content&#39;, &#39;&lt;&#39;, $filter[&#39;content&#39;]),<br>                    FilterOperator::GreaterThanOrEqual =&gt; $query-&gt;where(&#39;content&#39;, &#39;&gt;=&#39;, $filter[&#39;content&#39;]),<br>                    FilterOperator::LessThanOrEqual =&gt; $query-&gt;where(&#39;content&#39;, &#39;&lt;=&#39;, $filter[&#39;content&#39;]),<br>                };<br>            });<br>        }<br>        return $query;<br>    }<br>}</pre><h4>Executing the Query</h4><p>With the above setup, filtering profiles based on ProfileRows becomes straightforward:</p><pre>$filters = [<br> [<br> &#39;name&#39; =&gt; &#39;Phone&#39;,<br> &#39;operator&#39; =&gt; &#39;contains&#39;,<br> &#39;content&#39; =&gt; &#39;+45&#39;,<br> ],<br> [<br> &#39;name&#39; =&gt; &#39;firstname&#39;,<br> &#39;operator&#39; =&gt; &#39;equals&#39;,<br> &#39;content&#39; =&gt; &#39;Kim&#39;,<br> ],<br>];<br><br>$profiles = Client::find(1)-&gt;profiles()-&gt;withProfileRowsFilters($filters)-&gt;get();</pre><h3>Conclusion</h3><p>This approach to metadata filtering in Laravel leverages the framework’s built-in features, like Eloquent scopes, and the robustness of PHP Enums, to create a flexible and reusable solution without additional dependencies. While the focus here was on a specific use case, the principles can be applied to a wide range of scenarios, making your Laravel applications more versatile and maintainable.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=718b5cea0daa" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>