<?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[The dev journal]]></title><description><![CDATA[The dev journal]]></description><link>https://devjournals.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 31 Aug 2026 11:52:29 GMT</lastBuildDate><atom:link href="https://devjournals.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Embracing the Challenge: Building My PHP Framework from Scratch]]></title><description><![CDATA[Introduction
For the longest time, I harbored a deep-seated desire to create my own PHP framework, a personal venture that always seemed just out of reach due to self-doubt and the lingering effects of imposter syndrome. Despite years of experience, ...]]></description><link>https://devjournals.hashnode.dev/embracing-the-challenge-building-my-php-framework-from-scratch</link><guid isPermaLink="true">https://devjournals.hashnode.dev/embracing-the-challenge-building-my-php-framework-from-scratch</guid><category><![CDATA[PHP]]></category><category><![CDATA[patterns]]></category><category><![CDATA[clean code]]></category><category><![CDATA[services]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[Databases]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[mattia toselli]]></dc:creator><pubDate>Tue, 20 Feb 2024 15:33:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/-xTBn1YBrTE/upload/622943bc35f2206b3fc0fe792a617830.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>For the longest time, I harbored a deep-seated desire to create my own PHP framework, a personal venture that always seemed just out of reach due to self-doubt and the lingering effects of imposter syndrome. Despite years of experience, there was always something holding me back. The opportunity finally presented itself when I found myself tasked with revamping an entire application for a project, armed with only SFTP access and no availability of Composer. The previous developers had left behind a chaotic tangle of spaghetti code that needed a complete overhaul.</p>
<p>As I anticipated becoming the head of the dedicated unit for this project in the future, I foresaw the need for others, potentially young and inexperienced, to collaborate on it. Given the lack of stringent time constraints and the complete freedom to innovate, I saw this as the perfect opportunity to build something not only usable by everyone with minimal context but also to guide future colleagues down a path that would make long-term collaboration feasible. This was my chance to craft a framework that struck a balance between accessibility and a structure that would withstand the test of time.</p>
<p>This article is not going to be an easy one, there is a lot of stuff to cover and I am not going into the details of the basics, so if you are a beginner in PHP you may encounter many challenges, you may read it and find inspiration to improve in some arguments tough.</p>
<h2 id="heading-the-requirements">The requirements</h2>
<p>Here I will gather what I wanted to come up with at the end of the day.</p>
<ol>
<li><p>I was forced not to use composer, but I wanted to use namespacing.</p>
</li>
<li><p>I wanted my framework to be light and very easy to setup and use.</p>
</li>
<li><p>It had to be opinionated and more strict as possible.</p>
</li>
<li><p>I wanted to respect MVC pattern but also have the possibility to have json responses for API based projects.</p>
</li>
<li><p>My project has to be similar to Laravel and Symfony, taking the best of both of them.</p>
</li>
</ol>
<p>With this in mind, I hope I was able to get your attention, and I hope you will follow me in this challenge.</p>
<h2 id="heading-projects-structure-and-rewrite-rules"><strong>Project's structure and rewrite rules</strong></h2>
<p>The most important thing of a new framework is the structure we want to give to the different folders, what they will contain, how to access them, etc.</p>
<p>Another important thing is the security issues we may encounter, and also how much easy is to understand the structure properly. I came out with this:</p>
<p><img src="https://cdn.devdojo.com/images/january2024/Screenshot%202024-01-29%20120423.png" alt="Screenshot 2024-01-29 120423.png" /></p>
<p>The server is configured in order to point to the public folder, this is the only accessible one.</p>
<p>The most important thing is that in the public folder we will put only the index.php file, and an .htaccess file, doing something different could lead to potential security issues, because other folders could be accessible from the outside, we don't want that to happen.</p>
<p>This is a simple .htaccess file you can put in the public folder.</p>
<pre><code class="lang-apache"> <span class="hljs-comment"># Enable the rewriting engine</span>
 <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteEngine</span></span> <span class="hljs-literal">on</span>
 <span class="hljs-comment"># Check if the requested filename is not a regular file</span>
 <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond</span></span> <span class="hljs-variable">%{REQUEST_FILENAME}</span> !-f
 <span class="hljs-comment"># Check if the requested filename is not a directory</span>
 <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond</span></span> <span class="hljs-variable">%{REQUEST_FILENAME}</span> !-d
 <span class="hljs-comment"># Rewrite the URL to pass the path as a query parameter to index.php</span>
 <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteRule</span></span> ^(.*)$ /index.php?path=$<span class="hljs-number">1</span><span class="hljs-meta"> [NC,L,QSA]</span>
</code></pre>
<p>you may want to read these very good post to get used to the <a target="_blank" href="https://acquia.my.site.com/s/article/360005257234-Introduction-to-htaccess-rewrite-rules"><strong>Rewrite syntax</strong></a>.</p>
<p>From now on, every request will be redirected to the index.php file in the public folder.</p>
<p>We will need some kind of router to give proper response then, we will return on it later, let us first explore the other folders.</p>
<p>The Configuration folder contains the app configuration file, like database credentials, tokens, and other informations.</p>
<p>Core is the store folder for all the basic futures like routing, utility functions, validations, etc. You can see it as the actual kernel of the framework.</p>
<p>Controllers and Views will contain the controllers and the html files if we decide that we want to use this framework in an MVC project, but we could also decide to leave the view folder completely empty and use this project only for APIs.</p>
<p>We will return lately on the other parts.</p>
<h2 id="heading-namespacing-and-autoload"><strong>Namespacing and autoload</strong></h2>
<p>Usually, composer would be in charge to take care of autoloading classes and giving you access to namespacing, but as I mentioned before, we will not be allowed to use composer here, only vanilla allowed here.</p>
<p>Luckily, php has a very useful function for that, the infamous spl_autoload_register function, you may want to read the php documentation online, just google it. In order to use that, let us create the index.php and a functions file:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span>/index.php
<span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">const</span> BASE_PATH = <span class="hljs-keyword">__DIR__</span>.<span class="hljs-string">'/../'</span>;

<span class="hljs-keyword">require</span> BASE_PATH.<span class="hljs-string">"Core/functions.php"</span>;

spl_autoload_register(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$class</span>)</span>{
    $class = str_replace(<span class="hljs-string">'\\'</span>, DIRECTORY_SEPARATOR, $class);

    <span class="hljs-keyword">require</span> base_path($class.<span class="hljs-string">".php"</span>);
});
</code></pre>
<pre><code class="lang-php">Core/functions.php
<span class="hljs-meta">&lt;?php</span>

<span class="hljs-comment">/**
 * get the base path
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">base_path</span>(<span class="hljs-params">$path</span>)
</span>{
    <span class="hljs-keyword">return</span> BASE_PATH.$path;
}
</code></pre>
<p>This should be enough, if you try to access to different routes you should always be redirected to the index.php file, without errors or exceptions.</p>
<h2 id="heading-the-router">The Router</h2>
<p>I wanted a pretty basic but extensible router, this was a functionality in which I did not wanted to lose much time, of course there are better solutions out there, but I am pretty satisfied with mine. Remember that now we are allowed to (and should) use the namespacing.</p>
<pre><code class="lang-php">Core/Router.php
<span class="hljs-meta">&lt;?php</span>

<span class="hljs-comment">//set the namespace</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">Core</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Router</span>
</span>{
    <span class="hljs-comment">// Array to store the routes</span>
    <span class="hljs-keyword">protected</span> $routes = <span class="hljs-keyword">array</span>();

    <span class="hljs-comment">// Add a new route to the routes array</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addRoute</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $uri, <span class="hljs-keyword">string</span> $controller, <span class="hljs-keyword">string</span> $method</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;routes[] = <span class="hljs-keyword">array</span>(
            <span class="hljs-string">"uri"</span> =&gt; $uri,
            <span class="hljs-string">"controller"</span> =&gt; $controller,
            <span class="hljs-string">"method"</span> =&gt; $method,
        );
    }

    <span class="hljs-comment">// Add a GET route</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $uri, <span class="hljs-keyword">string</span> $controller</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;addRoute($uri, $controller, <span class="hljs-string">"GET"</span>);
    }

    <span class="hljs-comment">// Add a POST route</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">post</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $uri, <span class="hljs-keyword">string</span> $controller</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;addRoute($uri, $controller, <span class="hljs-string">"POST"</span>);
    }

    <span class="hljs-comment">// Add a PATCH route</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">patch</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $uri, <span class="hljs-keyword">string</span> $controller</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;addRoute($uri, $controller, <span class="hljs-string">"PATCH"</span>);
    }

    <span class="hljs-comment">// Add a PUT route</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">put</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $uri, <span class="hljs-keyword">string</span> $controller</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;addRoute($uri, $controller, <span class="hljs-string">"PUT"</span>);
    }

    <span class="hljs-comment">// Add a DELETE route</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delete</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $uri, <span class="hljs-keyword">string</span> $controller</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;addRoute($uri, $controller, <span class="hljs-string">"DELETE"</span>);
    }

    <span class="hljs-comment">// Route the request to the appropriate controller</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">route</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $uri</span>)
    </span>{
        $method = $_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>];
        $selectedRoute = <span class="hljs-literal">null</span>;
        <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">$this</span>-&gt;routes <span class="hljs-keyword">as</span> $route) {
            <span class="hljs-keyword">if</span>($route[<span class="hljs-string">'uri'</span>] === $uri) {
                <span class="hljs-comment">// Set the selected route</span>
                $selectedRoute = $route;
            }
        }
        <span class="hljs-comment">// If no valid route is selected, throw a 404 error</span>
        <span class="hljs-keyword">if</span>($selectedRoute === <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">Exception</span>(<span class="hljs-string">"Error 404. "</span>, <span class="hljs-number">1</span>);
        }

        <span class="hljs-comment">// If the method is not allowed, throw an exception</span>
        <span class="hljs-keyword">if</span>($selectedRoute[<span class="hljs-string">'method'</span>] !== $method) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">Exception</span>(<span class="hljs-string">"Method not allowed"</span>, <span class="hljs-number">1</span>);
        }

        <span class="hljs-comment">// Require and return the selected controller</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">require</span>(base_path($selectedRoute[<span class="hljs-string">'controller'</span>]));
    }

}
</code></pre>
<p>that's it, now we can register routes in our index.php file:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span>/index.php
<span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">Core</span>\<span class="hljs-title">Router</span>;

<span class="hljs-keyword">const</span> BASE_PATH = <span class="hljs-keyword">__DIR__</span>.<span class="hljs-string">'/../'</span>;

<span class="hljs-keyword">require</span> BASE_PATH.<span class="hljs-string">"Core/functions.php"</span>;

spl_autoload_register(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$class</span>)</span>{
    $class = str_replace(<span class="hljs-string">'\\'</span>, DIRECTORY_SEPARATOR, $class);

    <span class="hljs-keyword">require</span> base_path($class.<span class="hljs-string">".php"</span>);
});

<span class="hljs-comment">//defining routes</span>
$router = <span class="hljs-keyword">new</span> Router();
$router-&gt;post(<span class="hljs-string">"/test"</span>, <span class="hljs-string">"Controllers/TestController.php"</span>);
$router-&gt;get(<span class="hljs-string">"/home"</span>, <span class="hljs-string">"Controllers/HomeController.php"</span>);

<span class="hljs-comment">//route interpreter</span>
$uri = parse_url($_SERVER[<span class="hljs-string">'REQUEST_URI'</span>])[<span class="hljs-string">'path'</span>];
<span class="hljs-comment">//resolve request</span>
$router-&gt;route($uri);
</code></pre>
<p>registering a new route will be very easy, we just need to add a new line, the only caveat is that no equal path is allowed for different methods, you may want to tweak the code a little bit if you need this feature, to me it was completely fine.</p>
<pre><code class="lang-php">$router-&gt;method(<span class="hljs-string">"/route"</span>, <span class="hljs-string">"Controllers/path_to_controller"</span>);
</code></pre>
<h2 id="heading-controllers">Controllers</h2>
<p>We all know what controllers are used for, they will be in charge for the logic of the application. They usually query data, work on them, do calculations, and present them in a format suitable for the app.</p>
<p>The main choice is to decide if we prefer a controller to be in charge for a single use, or if we want to split them in different methods available for different routes. I went for the first choice, because i think it will generate less confusion and is less bug prone.</p>
<p>As you may see in the Router class, after a controller is registered and coupled to an endpoint, it is available to the route() method, this will require and execute the correct file.</p>
<h2 id="heading-response">Response</h2>
<p>The idea behind a backend is of course to provide a response, be it an HTML file, a csv, an xml, etc. We will firstly focus on every format except the HTML file, that is going to be treated in it's paragraph.</p>
<p>I created the in the Core namespace the Response class, I'll provide the code below.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">Core</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Response</span> 
</span>{
    <span class="hljs-comment">// Set the HTTP response code</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">status</span>(<span class="hljs-params">$statusCode</span>)
    </span>{
        http_response_code($statusCode);
    }

    <span class="hljs-comment">// Set the response header as JSON and print the data as JSON</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">jsonResponse</span>(<span class="hljs-params">$data</span>)
    </span>{
        header(<span class="hljs-string">'Content-Type: application/json'</span>);
        <span class="hljs-keyword">echo</span> json_encode($data);
    }

    <span class="hljs-comment">// Set the response header as CSV and print the data as CSV</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">csvResponse</span>(<span class="hljs-params">$data, $includeHeaders = <span class="hljs-literal">false</span></span>)
    </span>{
        header(<span class="hljs-string">'Content-Type: text/csv'</span>);
        <span class="hljs-keyword">if</span> ($includeHeaders) {
            $headers = array_keys($data[<span class="hljs-number">0</span>]);
            $output = fopen(<span class="hljs-string">'php://output'</span>, <span class="hljs-string">'w'</span>);
            fputcsv($output, $headers);
            <span class="hljs-keyword">foreach</span> ($data <span class="hljs-keyword">as</span> $row) {
                fputcsv($output, $row);
            }
            fclose($output);
        } <span class="hljs-keyword">else</span> {
            $output = fopen(<span class="hljs-string">'php://output'</span>, <span class="hljs-string">'w'</span>);
            <span class="hljs-keyword">foreach</span> ($data <span class="hljs-keyword">as</span> $row) {
                fputcsv($output, $row);
            }
            fclose($output);
        }
    }
}
</code></pre>
<p>the Response class is a good way to abstract this important feature of my framework, it provides an elegant way to send a response to the client. Look how easy is to do it:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">Core</span>\<span class="hljs-title">Response</span>;

<span class="hljs-comment">// create people's array</span>
$data = <span class="hljs-keyword">array</span>(
    <span class="hljs-keyword">array</span>(<span class="hljs-string">"firstname"</span> =&gt; <span class="hljs-string">"Mario"</span>, <span class="hljs-string">"name"</span> =&gt; <span class="hljs-string">"Rossi"</span>, <span class="hljs-string">"age"</span> =&gt; <span class="hljs-number">30</span>),
    <span class="hljs-keyword">array</span>(<span class="hljs-string">"firstname"</span> =&gt; <span class="hljs-string">"Anna"</span>, <span class="hljs-string">"name"</span> =&gt; <span class="hljs-string">"Verdi"</span>, <span class="hljs-string">"age"</span> =&gt; <span class="hljs-number">25</span>),
    <span class="hljs-keyword">array</span>(<span class="hljs-string">"firstname"</span> =&gt; <span class="hljs-string">"Luca"</span>, <span class="hljs-string">"name"</span> =&gt; <span class="hljs-string">"Bianchi"</span>, <span class="hljs-string">"age"</span> =&gt; <span class="hljs-number">28</span>)
);

$response = <span class="hljs-keyword">new</span> Response();
$response-&gt;status(<span class="hljs-number">200</span>);
$response-&gt;jsonResponse($data);
<span class="hljs-keyword">exit</span>();
</code></pre>
<p>if we use the csvResponse method we will obtain a csv file.</p>
<h2 id="heading-views">Views</h2>
<p>Often in traditional PHP code, loading a view after executing control logic involves using the include or require statement. However, this practice can become cluttered and less flexible as the application grows in complexity.</p>
<p>To simplify this operation and improve code modularity and maintainability, a utility function like view() can be created.</p>
<pre><code class="lang-php">Core/functions.php
<span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">/**
 * get the base path
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">base_path</span>(<span class="hljs-params">$path</span>)
</span>{
    <span class="hljs-keyword">return</span> BASE_PATH.$path;
}

<span class="hljs-comment">/**
 * returns the view
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">view</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $path, <span class="hljs-keyword">array</span> $params=[]</span>)
</span>{
    <span class="hljs-comment">//extract the params so that they are accessible in the view</span>
    extract($params);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">require</span>(base_path(<span class="hljs-string">"Views/"</span>.$path.<span class="hljs-string">".php"</span>));
}
</code></pre>
<p>This function accepts the path of the view to load and, optionally, an array of parameters that will be made available within the view itself.</p>
<p>The <code>extract()</code> function is used within <code>view()</code> to extract variables from the parameters array, making them directly accessible within the view. In practice, <code>extract()</code> transforms each key of the array into a variable, with the key itself serving as the variable name, and assigns the corresponding value to that variable.</p>
<h2 id="heading-models-and-database">Models and Database</h2>
<p>The last argument we have to cover, is the database. One of the most clean and reusable approach is the Repository Service Pattern. I won't cover the topic here, I will just cover how i implemented it using also the Models approach.</p>
<p>This lead us to an important subject: the configuration. There are many approaches that we can take, the most important thing is to create a way to access the configurations we need but to never expose the informations outside. One of the best approach is to use environment variables, so I created a Configuration class like this:</p>
<pre><code class="lang-php">Configuration/Configuration.php
<span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Configuration</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Configuration</span>
</span>{

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> [
            <span class="hljs-string">"database"</span> =&gt; [
                <span class="hljs-string">"username"</span> =&gt; getenv(<span class="hljs-string">'DB_USERNAME'</span>) ?: <span class="hljs-string">'put here a default username if you want'</span>,
                <span class="hljs-string">"port"</span> =&gt; getenv(<span class="hljs-string">'DB_PORT'</span>) ?: <span class="hljs-number">3306</span>,
                <span class="hljs-string">"password"</span> =&gt; getenv(<span class="hljs-string">'DB_PASSWORD'</span>) ?: <span class="hljs-string">''</span>,
                <span class="hljs-string">"host"</span> =&gt; getenv(<span class="hljs-string">'DB_HOST'</span>) ?: <span class="hljs-string">'127.0.0.1'</span>,
                <span class="hljs-string">"db_name"</span> =&gt; getenv(<span class="hljs-string">"DB_NAME"</span>) ?: <span class="hljs-string">"db_name"</span>,
            ]
        ];
    }
}
</code></pre>
<p>Next, the Database class to provide an abstraction layer:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Core</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Configuration</span>\<span class="hljs-title">Configuration</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Database</span>
</span>{
    <span class="hljs-keyword">protected</span> <span class="hljs-built_in">static</span> $connection;

    <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>)
    </span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">static</span>::$connection === <span class="hljs-literal">null</span>) {
            $config = <span class="hljs-keyword">new</span> Configuration();
            $config = $config-&gt;get();
            $username = $config[<span class="hljs-string">'database'</span>][<span class="hljs-string">'username'</span>];
            $password = $config[<span class="hljs-string">'database'</span>][<span class="hljs-string">'password'</span>];
            $host = $config[<span class="hljs-string">'database'</span>][<span class="hljs-string">'host'</span>];
            $port = $config[<span class="hljs-string">'database'</span>][<span class="hljs-string">'port'</span>];
            $db_name = $config[<span class="hljs-string">'database'</span>][<span class="hljs-string">'db_name'</span>];

            $dsn = <span class="hljs-string">"mysql:host=<span class="hljs-subst">$host</span>;port=<span class="hljs-subst">$port</span>;dbname=<span class="hljs-subst">$db_name</span>"</span>;

            $options = [
                \PDO::ATTR_ERRMODE =&gt; \PDO::ERRMODE_EXCEPTION,
                \PDO::ATTR_DEFAULT_FETCH_MODE =&gt; \PDO::FETCH_ASSOC,
            ];
            <span class="hljs-built_in">static</span>::$connection = <span class="hljs-keyword">new</span> \PDO($dsn, $username, $password, $options);
        }
    }

    <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">$queryString</span>)
    </span>{
        $statement = <span class="hljs-built_in">static</span>::$connection-&gt;query($queryString);
        <span class="hljs-keyword">return</span> $statement;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">prepare</span>(<span class="hljs-params">$queryString</span>)
    </span>{
        $statement = <span class="hljs-built_in">static</span>::$connection-&gt;prepare($queryString);
        <span class="hljs-keyword">return</span> $statement;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lastInsertId</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">static</span>::$connection-&gt;lastInsertId();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">beginTransaction</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-built_in">static</span>::$connection-&gt;beginTransaction();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">commit</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-built_in">static</span>::$connection-&gt;commit();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rollBack</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-built_in">static</span>::$connection-&gt;rollBack();
    }
}
</code></pre>
<h2 id="heading-models">Models</h2>
<p>I find that using getters and setters on models is a bit verbose, I prefer the Laravel approach, of course is up to you which one you prefer, in my case I used the same approach of Laravel, so by using magic methods.</p>
<p>Another thing I wanted, was to be sure that if someone tries to get or set a property that was not correspondent to a column on the database would lead to an error.</p>
<p>I came up with this class:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Models</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Core</span>\<span class="hljs-title">Database</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-comment">//informations needed in every model</span>
    <span class="hljs-keyword">protected</span> $tablename;
    <span class="hljs-keyword">protected</span> $primaryKey;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getClassName</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">static</span>::class;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__set</span>(<span class="hljs-params">$name, $value</span>)
    </span>{
        $className = <span class="hljs-built_in">self</span>::getClassName();
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">InvalidArgumentException</span>(<span class="hljs-string">"Property \"<span class="hljs-subst">$name</span>\" does not exists in Model <span class="hljs-subst">$className</span>."</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__get</span>(<span class="hljs-params">$name</span>)
    </span>{
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">InvalidArgumentException</span>(<span class="hljs-string">"Property \"<span class="hljs-subst">$name</span>\" does not exists in Model <span class="hljs-subst">$className</span>."</span>);
    }
}
</code></pre>
<p>Now, everytime we create a table, we can have the correspondent model class, and we are forced to implement the most important informations, like the name of the primary key, the table name, and the column names.</p>
<p>We will work with a User class as an example:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Models</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">public</span> $id;
    <span class="hljs-keyword">public</span> $email;
    <span class="hljs-keyword">public</span> $first_name;
    <span class="hljs-keyword">public</span> $last_name;
    <span class="hljs-keyword">public</span> $role;
    <span class="hljs-keyword">public</span> $email_verify_token;
    <span class="hljs-keyword">public</span> $email_token_date;
    <span class="hljs-keyword">public</span> $email_verified_at;
    <span class="hljs-keyword">public</span> $last_login;
    <span class="hljs-keyword">public</span> $password;
    <span class="hljs-keyword">public</span> $password_reset_token;
    <span class="hljs-keyword">public</span> $password_reset_token_at;
    <span class="hljs-keyword">public</span> $created_at;
    <span class="hljs-keyword">public</span> $updated_at;
}
</code></pre>
<h2 id="heading-repository-service-pattern-and-traits">Repository Service Pattern and Traits</h2>
<p>I decided for my own implementation of the Repository Service Pattern, we will follow the example with the User model used before.</p>
<p>I won't cover the pros and cons of this programming standard, if you are not used to it, I friendly invite you to read some great articles about it that you may find on the web, I also wanted to split my code in different files, in order not to have duplications in every repository.</p>
<p>To do that, I had to use Traits, I find them very useful and I genuinely invite everyone who wants to write clean code to have a read at the documentation of PHP and get used to this feature.</p>
<p>Let's start with the read operations on the database, the first thing we need in the pattern, in an interface for these operations:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Repositories</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Models</span>\<span class="hljs-title">Model</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">RepositoryInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">all</span>(<span class="hljs-params"></span>) : <span class="hljs-title">array</span></span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">find</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $value</span>) : ?<span class="hljs-title">Model</span></span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findMany</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $value</span>) : <span class="hljs-title">array</span></span>;
}
</code></pre>
<p>Everytime we want to create another table in the database, now, we will have to create the corresponding model, with all the fields listed in the class, let us for example create another class, the Migration model:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Models</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Migration</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">public</span> $id;
    <span class="hljs-keyword">public</span> $migration;
    <span class="hljs-keyword">public</span> $batch;
}
</code></pre>
<p>then, we need to create an interface that extends the general one, this one is in charge only for the entity on the database, so we will create the UserRepositoryInterface and the MigrationRepositoryInterface classes:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Repositories</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Repositories</span>\<span class="hljs-title">RepositoryInterface</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Models</span>\<span class="hljs-title">Model</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepositoryInterface</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">RepositoryInterface</span>
</span>{

}
</code></pre>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Repositories</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Repositories</span>\<span class="hljs-title">RepositoryInterface</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Models</span>\<span class="hljs-title">Model</span>;

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">MigrationRepositoryInterface</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">RepositoryInterface</span>
</span>{

}
</code></pre>
<p>these interfaces may also contain other methods, that may be useful only for some of our database entities, usually I don't see any reason to provide more methods than just the simple CRUD operations, but never say never.</p>
<p>Next, we have the actual last implementation of the repository.</p>
<p>In my project we had to deal only with an SQL database, but if someday we will have also to deal with Users or Patients scattered in, let's say as an example, an SQL and a MONGO database, the only thing that we have to do, will be to extend the UserRepositoryInterface (or the Migration one), and provide somehow the methods to access the mongo instance in the other classe, let's say the UserMongodbRepository, or the name that you may prefer.</p>
<p>Let us now create the repositories that will be in charge for the mysql database, we will understand after the explanation what the ModelQueriable trait is:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Repositories</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Models</span>\<span class="hljs-title">User</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Core</span>\<span class="hljs-title">Database</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Traits</span>\<span class="hljs-title">ModelQueriable</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserRepositoryInterface</span>
</span>{
    <span class="hljs-keyword">protected</span> $tablename = <span class="hljs-string">"users"</span>;
    <span class="hljs-keyword">protected</span> $primaryKey = <span class="hljs-string">"id"</span>;
    <span class="hljs-keyword">protected</span> $model = <span class="hljs-string">"Models\User"</span>;
    <span class="hljs-keyword">protected</span> $database;

    <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>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;database = <span class="hljs-keyword">new</span> Database();
    }

    <span class="hljs-keyword">use</span> <span class="hljs-title">ModelQueriable</span>;

}
</code></pre>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Repositories</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Models</span>\<span class="hljs-title">User</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Core</span>\<span class="hljs-title">Database</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Traits</span>\<span class="hljs-title">ModelQueriable</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MigrationRepository</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">MigrationRepositoryInterface</span>
</span>{
    <span class="hljs-keyword">protected</span> $tablename = <span class="hljs-string">"migrations"</span>;
    <span class="hljs-keyword">protected</span> $primaryKey = <span class="hljs-string">"id"</span>;
    <span class="hljs-keyword">protected</span> $model = <span class="hljs-string">"Models\Migration"</span>;
    <span class="hljs-keyword">protected</span> $database;

    <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>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;database = <span class="hljs-keyword">new</span> Database();
    }
    <span class="hljs-keyword">use</span> <span class="hljs-title">ModelQueriable</span>;
}
</code></pre>
<h2 id="heading-implement-services-and-traits">Implement services and traits</h2>
<p>Using traits in PHP offers several advantages. Firstly, traits allow for code reusability by enabling developers to define methods that can be reused across multiple classes without inheritance limitations. This promotes cleaner and more modular code, as common functionality can be encapsulated within traits and easily included wherever needed.</p>
<p>One good example is the fact that we may want to add the read functions (read all, read many, read by id) to different repositories, but not everyone of them, in a clean way. Thast's why I created a Trait for that.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Traits</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Models</span>\<span class="hljs-title">Model</span>;

<span class="hljs-keyword">trait</span> ModelQueriable
{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">all</span>(<span class="hljs-params"></span>): <span class="hljs-title">array</span>
    </span>{
        $result = <span class="hljs-keyword">array</span>();
        <span class="hljs-comment">//execute the query</span>
        $statement = <span class="hljs-keyword">$this</span>-&gt;database-&gt;query(<span class="hljs-string">"select * from <span class="hljs-subst">$this</span>-&gt;tablename"</span>);
        $statement-&gt;execute();
        $data = $statement-&gt;fetchAll();

        <span class="hljs-comment">//instanciate and return a set of models</span>
        <span class="hljs-keyword">foreach</span> ($data <span class="hljs-keyword">as</span> $row) {
            $record = <span class="hljs-keyword">new</span> <span class="hljs-keyword">$this</span>-&gt;model();
            <span class="hljs-keyword">foreach</span> ($row <span class="hljs-keyword">as</span> $column =&gt; $value) {
                $record-&gt;$column = $value;
            }
            $result[] = $record;
        }
        <span class="hljs-keyword">return</span> $result;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">find</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $id</span>) : ?<span class="hljs-title">Model</span>
    </span>{
        $table = <span class="hljs-keyword">$this</span>-&gt;tablename;
        $key = <span class="hljs-keyword">$this</span>-&gt;primaryKey;
        $statement = <span class="hljs-keyword">$this</span>-&gt;database-&gt;prepare(<span class="hljs-string">"SELECT * FROM <span class="hljs-subst">$table</span> WHERE <span class="hljs-subst">$key</span> = :id"</span>);
        $statement-&gt;bindValue(<span class="hljs-string">':id'</span>, $id);
        $statement-&gt;execute();
        $data = $statement-&gt;fetchAll();
        <span class="hljs-keyword">if</span>(<span class="hljs-keyword">empty</span>($data[<span class="hljs-number">0</span>])) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
        }
        $record = <span class="hljs-keyword">new</span> <span class="hljs-keyword">$this</span>-&gt;model();
        <span class="hljs-keyword">foreach</span> ($data[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> $column =&gt; $value) {
            $record-&gt;$column = $value;
        }
        <span class="hljs-keyword">return</span> $record;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findMany</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $ids</span>): <span class="hljs-title">array</span>
    </span>{
        $table = <span class="hljs-keyword">$this</span>-&gt;tablename;
        $key = <span class="hljs-keyword">$this</span>-&gt;primaryKey;
        $idsString = implode(<span class="hljs-string">","</span>, $ids);
        $sql = <span class="hljs-string">"SELECT * FROM <span class="hljs-subst">$table</span> WHERE <span class="hljs-subst">$key</span> IN (<span class="hljs-subst">$idsString</span>)"</span>;
        $statement = <span class="hljs-keyword">$this</span>-&gt;database-&gt;query($sql);
        $statement-&gt;execute();
        $data = $statement-&gt;fetchAll();

        $result = <span class="hljs-keyword">array</span>();
        <span class="hljs-keyword">foreach</span> ($data <span class="hljs-keyword">as</span> $row) {
            $record = <span class="hljs-keyword">new</span> <span class="hljs-keyword">$this</span>-&gt;model();
            <span class="hljs-keyword">foreach</span> ($row <span class="hljs-keyword">as</span> $column =&gt; $value) {
                $record-&gt;$column = $value;
            }
            $result[] = $record;
        }
        <span class="hljs-keyword">return</span> $result;
    }
}
</code></pre>
<p>Everytime we use the trait, it will be like doing a sort of ctrl+c and ctrl+v but without the duplication problems.</p>
<p>Now, we can use the services to interact with the repositories:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Services</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Models</span>\<span class="hljs-title">User</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Repositories</span>\<span class="hljs-title">UserRepository</span>;

<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span>
</span>{
    <span class="hljs-keyword">protected</span> <span class="hljs-built_in">static</span> $UserRepository;

    <span class="hljs-keyword">protected</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initialize</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-built_in">self</span>::$UserRepository = <span class="hljs-keyword">new</span> UserRepository();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">find</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $id</span>): ?<span class="hljs-title">User</span>
    </span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">self</span>::$UserRepository == <span class="hljs-literal">null</span>) {
            <span class="hljs-built_in">self</span>::initialize();
        }
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::$UserRepository-&gt;find($id);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">all</span>(<span class="hljs-params"></span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">self</span>::$UserRepository == <span class="hljs-literal">null</span>) {
            <span class="hljs-built_in">self</span>::initialize();
        }
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::$UserRepository-&gt;all();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findMany</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $ids</span>) : <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">self</span>::$UserRepository == <span class="hljs-literal">null</span>) {
            <span class="hljs-built_in">self</span>::initialize();
        }
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::$UserRepository-&gt;findMany($ids);
    }
}
</code></pre>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Services</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Models</span>\<span class="hljs-title">Migration</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Repositories</span>\<span class="hljs-title">MigrationRepository</span>;

<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MigrationService</span>
</span>{
    <span class="hljs-keyword">protected</span> <span class="hljs-built_in">static</span> $MigrationRepository;

    <span class="hljs-keyword">protected</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initialize</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-built_in">self</span>::$MigrationRepository = <span class="hljs-keyword">new</span> MigrationRepository();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">find</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $id</span>): ?<span class="hljs-title">User</span>
    </span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">self</span>::$MigrationRepository == <span class="hljs-literal">null</span>) {
            <span class="hljs-built_in">self</span>::initialize();
        }
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::$MigrationRepository-&gt;find($id);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">all</span>(<span class="hljs-params"></span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">self</span>::$MigrationRepository == <span class="hljs-literal">null</span>) {
            <span class="hljs-built_in">self</span>::initialize();
        }
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::$MigrationRepository-&gt;all();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findMany</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $ids</span>) : <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">self</span>::$MigrationRepository == <span class="hljs-literal">null</span>) {
            <span class="hljs-built_in">self</span>::initialize();
        }
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::$MigrationRepository-&gt;findMany($ids);
    }
}
</code></pre>
<p>now we can execute queries in our controllers:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">Core</span>\<span class="hljs-title">Response</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Services</span>\<span class="hljs-title">MigrationService</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Core</span>\<span class="hljs-title">Password</span>;

$migration = MigrationService::all();

$response = <span class="hljs-keyword">new</span> Response();
$response-&gt;status(<span class="hljs-number">200</span>);
$response-&gt;jsonResponse($migration);
</code></pre>
<h2 id="heading-conclusions">Conclusions</h2>
<p>I really hope that this article was a nice read for you, if you have any advice, or complaining, please feel free to comment (kindly, I won't tolerate any rudeness, racism or insults).</p>
<p>Cheers.</p>
]]></content:encoded></item></channel></rss>