<?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"><channel><title><![CDATA[Mayank's Blog]]></title><description><![CDATA[Mayank's Blog]]></description><link>https://blog.mayankjani.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 16:49:44 GMT</lastBuildDate><atom:link href="https://blog.mayankjani.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Demystifying Value Objects in PHP]]></title><description><![CDATA[Value Objects are simple PHP classes that allow us to compare the values of an entity that could be in different formats. For example, money could be in multiple currencies, and it cannot be directly compared with just an amount.
Let’s dive right int...]]></description><link>https://blog.mayankjani.com/demystifying-value-objects-in-php</link><guid isPermaLink="true">https://blog.mayankjani.com/demystifying-value-objects-in-php</guid><category><![CDATA[PHP]]></category><category><![CDATA[value objects]]></category><category><![CDATA[Object Oriented Programming]]></category><dc:creator><![CDATA[Mayank Jani]]></dc:creator><pubDate>Mon, 07 Oct 2024 11:59:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728302312142/32431bcc-158e-4329-80a3-7bd4dd6e1511.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Value Objects are simple PHP classes that allow us to compare the values of an entity that could be in different formats. For example, money could be in multiple currencies, and it cannot be directly compared with just an amount.</p>
<p>Let’s dive right into an example!</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Money</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> readonly <span class="hljs-keyword">string</span> $amount,
        <span class="hljs-keyword">public</span> readonly <span class="hljs-keyword">string</span> $currency
    </span>)</span>{}

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">equals</span>(<span class="hljs-params">Money $money</span>): <span class="hljs-title">bool</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;amount === $money-&gt;amount &amp;&amp;
                <span class="hljs-keyword">$this</span>-&gt;currency === $money-&gt;currency;
    }
}

$tenDollar = <span class="hljs-keyword">new</span> Money(<span class="hljs-number">10</span>, <span class="hljs-string">'USD'</span>);
$tenRupee = <span class="hljs-keyword">new</span> Money(<span class="hljs-number">10</span>, <span class="hljs-string">'INR'</span>);

$tenDollar-&gt;equals($tenRupee); <span class="hljs-comment">// false</span>
</code></pre>
<p>As you can see value objects are just simple simple classes with a function that computes equality. Here we can specify our custom logic to compare entities.</p>
<p>Other bonus advantages of Value Objects:</p>
<ul>
<li><p>Can be used as DTOs to pass data around different services.</p>
</li>
<li><p>Reliable data due to readonly properties of the class which means the data cannot be changed.</p>
</li>
</ul>
<p>Hope this post makes it easier to understand Value Objects in PHP. I’ve kept it brief on purpose to not overcomplicate things.</p>
<p>If you have any questions, I will be happy to answer them in the comments.</p>
]]></content:encoded></item><item><title><![CDATA[Data Transfer Objects (DTOs) in PHP]]></title><description><![CDATA[Lets say, we have a news website and we want to display news which are nearby to the user. First we need to get the user’s location via an API and then pass it to the database query. We can use the API from https://ip-api.com
class IpApi{
    public ...]]></description><link>https://blog.mayankjani.com/data-transfer-objects-dtos-in-php</link><guid isPermaLink="true">https://blog.mayankjani.com/data-transfer-objects-dtos-in-php</guid><category><![CDATA[PHP]]></category><category><![CDATA[dto]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Mayank Jani]]></dc:creator><pubDate>Fri, 13 Sep 2024 08:31:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726204396276/bc4a2cc6-e48d-437a-96d2-ed97675ad586.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Lets say, we have a news website and we want to display news which are nearby to the user. First we need to get the user’s location via an API and then pass it to the database query. We can use the API from <a target="_blank" href="https://ip-api.com/">https://ip-api.com</a></p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IpApi</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLocation</span>(<span class="hljs-params"></span>): <span class="hljs-title">array</span></span>{
        <span class="hljs-comment">// Make an API call</span>
        <span class="hljs-comment">// Sample api Response from https://ip-api.com</span>
        <span class="hljs-keyword">return</span> [
            <span class="hljs-string">'countryCode'</span> =&gt; <span class="hljs-string">'US'</span>,
            <span class="hljs-string">'country'</span> =&gt; <span class="hljs-string">'United States'</span>,
            <span class="hljs-string">'city'</span> =&gt; <span class="hljs-string">'New York'</span>
        ];
    }
}
</code></pre>
<p>Now we have the API setup to fetch the user’s location via their IP address. Let’s now fetch news articles in user’s location.</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">News</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsService</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getNewsNearby</span>(<span class="hljs-params"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">array</span> $location</span>)</span>{
        <span class="hljs-keyword">return</span> News::where(<span class="hljs-string">'country'</span>, $location[<span class="hljs-string">'country'</span>])-&gt;where(<span class="hljs-string">'city'</span>, $location[<span class="hljs-string">'city'</span>])-&gt;get();
    }
}

<span class="hljs-comment">// Get the location</span>
$locationApi = <span class="hljs-keyword">new</span> IpApi;
$location = $locationApi-&gt;getLocation();

<span class="hljs-comment">// Fetch the news articles</span>
$newsService = <span class="hljs-keyword">new</span> NewsService;
$news = $newsService-&gt;getNewsNearby($location);
</code></pre>
<p>We should get the news articles in the user’s city. Everything works as expected.</p>
<p>Though what will happen if we change the API service in the future? Lets use <a target="_blank" href="https://ipgeolocation.io/">https://ipgeolocation.io</a> as an example.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IpGeolocationApi</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLocation</span>(<span class="hljs-params"></span>): <span class="hljs-title">array</span></span>{
        <span class="hljs-comment">// Make an API call</span>
        <span class="hljs-comment">// Sample api Response from https://ipgeolocation.io</span>
        <span class="hljs-keyword">return</span> [
            <span class="hljs-string">'country_code2'</span> =&gt; <span class="hljs-string">'US'</span>,
            <span class="hljs-string">'country_code3'</span> =&gt; <span class="hljs-string">'USA'</span>,
            <span class="hljs-string">'country_name'</span> =&gt; <span class="hljs-string">'United States'</span>,
            <span class="hljs-string">'city'</span> =&gt; <span class="hljs-string">'New York'</span>
        ];
    }
}
</code></pre>
<p>As you can see, the API response from https://ipgeolocation.io is a bit different and hence our previous code to fetch news will fail.</p>
<pre><code class="lang-php"><span class="hljs-comment">// This will now throw an error</span>

<span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">News</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsService</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getNewsNearby</span>(<span class="hljs-params"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">array</span> $location</span>)</span>{
        <span class="hljs-keyword">return</span> News::where(<span class="hljs-string">'country'</span>, $location[<span class="hljs-string">'country'</span>])-&gt;where(<span class="hljs-string">'city'</span>, $location[<span class="hljs-string">'city'</span>])-&gt;get();
    }
}
</code></pre>
<p>One simple solution is to change <code>$location['country']</code> to <code>$location['country_name']</code> and the code should work. But we will have the same issue whenever we change the API in the future. Also it might not be feasible to change the code if we are using it multiple places.</p>
<h2 id="heading-enter-dtos">Enter DTOs</h2>
<p>What if we can have our own data structure independent of APIs? Using DTOs, we can simply create a PHP class to hold user’s location.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LocationDTO</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> readonly <span class="hljs-keyword">string</span> $country, <span class="hljs-keyword">public</span> readonly <span class="hljs-keyword">string</span> $city</span>)</span>{
    }
}
</code></pre>
<p>Now we can use this class instead of raw API responses in array. We can also type hint fields like <code>$country</code> and <code>$city</code> so we always have the correct data format.</p>
<p>Additionally, <strong>readonly</strong> properties ensures that the property values cannot be changed once initialized. This solidifies that we will always have unaltered and accurate data. Readonly properties are supported in PHP 8.1 and later.</p>
<p>Now lets refactor our code a bit and implement DTOs. We need to do couple of things:</p>
<ol>
<li><p>Replace array with a DTO in api response when fetching location.</p>
</li>
<li><p>Replace array with a DTO when using location data in our application, like when fetching news articles.</p>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// Replace array with a DTO</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IpApi</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLocation</span>(<span class="hljs-params"></span>): <span class="hljs-title">LocationDTO</span></span>{
        <span class="hljs-comment">// Make an API call</span>
        <span class="hljs-comment">// Sample api Response from https://ip-api.com</span>
        $location = [
            <span class="hljs-string">'countryCode'</span> =&gt; <span class="hljs-string">'US'</span>,
            <span class="hljs-string">'country'</span> =&gt; <span class="hljs-string">'United States'</span>,
            <span class="hljs-string">'city'</span> =&gt; <span class="hljs-string">'New York'</span>
        ];

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> LocationDTO($location[<span class="hljs-string">'country'</span>], $location[<span class="hljs-string">'city'</span>]);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IpGeolocationApi</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLocation</span>(<span class="hljs-params"></span>): <span class="hljs-title">LocationDTO</span></span>{
        <span class="hljs-comment">// Make an API call</span>
        <span class="hljs-comment">// Sample api Response from https://ipgeolocation.io</span>
        $location = [
            <span class="hljs-string">'country_code2'</span> =&gt; <span class="hljs-string">'US'</span>,
            <span class="hljs-string">'country_code3'</span> =&gt; <span class="hljs-string">'USA'</span>,
            <span class="hljs-string">'country_name'</span> =&gt; <span class="hljs-string">'United States'</span>,
            <span class="hljs-string">'city'</span> =&gt; <span class="hljs-string">'New York'</span>
        ];

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> LocationDTO($location[<span class="hljs-string">'country_name'</span>], $location[<span class="hljs-string">'city'</span>]);
    }
}
</code></pre>
<p>Now we can return a DTO from the API response instead of an array. Let’s use it in our application to fetch news articles nearby to the user.</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">News</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsService</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getNewsNearby</span>(<span class="hljs-params"><span class="hljs-keyword">protected</span> LocationDTO $location</span>)</span>{
        <span class="hljs-keyword">return</span> News::where(<span class="hljs-string">'country'</span>, $location-&gt;country)-&gt;where(<span class="hljs-string">'city'</span>, $location-&gt;city)-&gt;get();
    }
}

<span class="hljs-comment">// Get the location</span>
$locationApi = <span class="hljs-keyword">new</span> IpApi;
$location  = $locationApi-&gt;getLocation();

<span class="hljs-comment">// Fetch the news articles</span>
$newsService = <span class="hljs-keyword">new</span> NewsService;
$news = $newsService-&gt;getNewsNearby($location);
</code></pre>
<p>Now if we change our API in the future, we just have to switch our API class and the data format will remain the same.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Get the location using https://ipgeolocation.io</span>
$locationApi = <span class="hljs-keyword">new</span> IpGelocationApi;
$location  = $locationApi-&gt;getLocation();

<span class="hljs-comment">// Fetch the news articles</span>
$newsService = <span class="hljs-keyword">new</span> NewsService;
$news = $newsService-&gt;getNewsNearby($location);
</code></pre>
<p>Note that we didn’t had to change our logic to fetch news from the database as it uses DTO which does not change. Similarly wherever we use DTO in our codebase, we won’t have to make a change which makes maintenance easier.</p>
<h2 id="heading-bonus-use-interface">Bonus: Use Interface</h2>
<p>In modern frameworks like Laravel, you can bind an interface to the concrete class. So instead of manuallly initializing an API like <code>new IpApi</code>, we can use an interface.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">LocationInterface</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLocation</span>(<span class="hljs-params"></span>): <span class="hljs-title">LocationDTO</span></span>;
}

<span class="hljs-keyword">$this</span>-&gt;app-&gt;bind(LocationInterface::class, IpApi::class);
</code></pre>
<p>Now you can fetch location in your code without using the IpApi class.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewsController</span></span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params">LocationInterface $location</span>)</span>{
        $newsService = <span class="hljs-keyword">new</span> NewsService;
        $news = $newsService-&gt;getNewsNearby($location);
    }
}
</code></pre>
<p>The benefit of this approach is you can change the API service in future with only one line of change.</p>
<pre><code class="lang-php"><span class="hljs-comment">//Use IpGelocationApi instead of IpApi</span>
<span class="hljs-keyword">$this</span>-&gt;app-&gt;bind(LocationInterface::class, IpGelocationApi::class);
</code></pre>
<p>Our controller will remain exactly as it is and it does not care which API service you are using.</p>
<p>This approach also satisfies 2 SOLID principles - Liskov Substitution Principle and Dependency Inversion Principle.</p>
<p>Hope this makes it easier to understand DTOs in PHP and how useful it can be. If you have any questions, I will be happy to answer them in the comments.</p>
]]></content:encoded></item><item><title><![CDATA[How to reuse database queries in Laravel]]></title><description><![CDATA[Often in database heavy applications in Laravel, we have numerous database queries to fetch various types of data. You might use them in controllers, services, console commands, admins, and other pieces of code. Often these queries are not organized ...]]></description><link>https://blog.mayankjani.com/how-to-reuse-database-queries-in-laravel</link><guid isPermaLink="true">https://blog.mayankjani.com/how-to-reuse-database-queries-in-laravel</guid><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Mayank Jani]]></dc:creator><pubDate>Wed, 11 Sep 2024 05:27:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726032742222/3b5da94f-4fe3-4467-b7fd-c3ba0e186be5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Often in database heavy applications in Laravel, we have numerous database queries to fetch various types of data. You might use them in controllers, services, console commands, admins, and other pieces of code. Often these queries are not organized and can lead to maintenance issues. Some of the issues you might already be facing are:</p>
<ul>
<li><p>Duplicate Queries: Repeating the same database query in multiple places, which makes it tricky to update them in the future as you will have to hunt them down every time you want to make a change.</p>
</li>
<li><p>Caching: Maintaining caches and invalidating them can be difficult if your database queries are scattered throughout the codebase.</p>
</li>
</ul>
<p>Lately in my projects, I have been using a technique.</p>
<h2 id="heading-the-solution">The Solution</h2>
<p>Turns out the solution is to quite simply refactor your queries into simple PHP classes and store them in a dedicated folder. I use App\Stores, but you can use App\Data or whatever makes the most sense to you.</p>
<pre><code class="lang-php"><span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Stores</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Builder</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">Movie</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TopRatedMovies</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">query</span>(<span class="hljs-params"></span>): <span class="hljs-title">Builder</span>
    </span>{
        <span class="hljs-keyword">return</span> Movie::orderByDesc(<span class="hljs-string">'rating'</span>);
    }
}
</code></pre>
<p>Now you can use database queries anywhere in your code.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TopRatedMoviesController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params">TopRatedMovies $topRatedMovies</span>)
    </span>{
        $movies = $topRatedMovies-&gt;get();
        ...
    }
}
</code></pre>
<h2 id="heading-refactoring-into-a-package">Refactoring into a package</h2>
<p>I refactored this solution into a package to use across different projects. It contains additional features like caching &amp; custom data types.</p>
<p>Check out the “Laravel Store“ package on <a target="_blank" href="https://github.com/mayankjanidev/laravel-store">GitHub</a>.</p>
<h2 id="heading-caching">Caching</h2>
<p>Every store has its own methods to manage cache.</p>
<pre><code class="lang-php">(<span class="hljs-keyword">new</span> TopRatedMovies)-&gt;getCachedData();
(<span class="hljs-keyword">new</span> TopRatedMovies)-&gt;cache();
(<span class="hljs-keyword">new</span> TopRatedMovies)-&gt;clearCache();
</code></pre>
<h2 id="heading-custom-data-types">Custom Data Types</h2>
<p>You might have some data in your application that is in a different format, like an array, and does not return a database query. In those cases, you can use a <code>CustomStore</code> where you can return data in your own format rather than being dependent on Laravel model and query builder.</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Mayank</span>\<span class="hljs-title">Store</span>\<span class="hljs-title">CustomStore</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Languages</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">CustomStore</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">data</span>(<span class="hljs-params"></span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">return</span> [<span class="hljs-string">'English'</span>, <span class="hljs-string">'Spanish'</span>, <span class="hljs-string">'French'</span>];
    }
}
</code></pre>
<h2 id="heading-cli">CLI</h2>
<p>If you manage your data via the command line or via <a target="_blank" href="https://laravel.com/docs/scheduling">Task Scheduling</a>, Laravel Store provides cache specific commands:</p>
<pre><code class="lang-php">php artisan store:cache TopRatedMovies
</code></pre>
<h2 id="heading-flexibility">Flexibility</h2>
<p>As we are simply using PHP classes, you have infinite flexibility to add more features to your database queries. Perhaps you need a method to get a slightly different version of the data exclusively for the apps? Or maybe you want to do some processing to the data? You can add as many methods as you need in your store class.</p>
<h2 id="heading-feedback">Feedback</h2>
<p>I hope this was useful to you. I would love to hear any feedback and know more about how you organize database queries in your application.</p>
]]></content:encoded></item></channel></rss>