<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Micael Vinhas</title>
    <description>The latest articles on Forem by Micael Vinhas (@mvinhas).</description>
    <link>https://forem.com/mvinhas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F48263%2F8ecb19cb-5683-49b9-bcd8-bc3975005bd9.jpg</url>
      <title>Forem: Micael Vinhas</title>
      <link>https://forem.com/mvinhas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mvinhas"/>
    <language>en</language>
    <item>
      <title>Simple routing system for a PHP MVC application</title>
      <dc:creator>Micael Vinhas</dc:creator>
      <pubDate>Tue, 16 Aug 2022 13:48:00 +0000</pubDate>
      <link>https://forem.com/mvinhas/simple-routing-system-for-a-php-mvc-application-16f7</link>
      <guid>https://forem.com/mvinhas/simple-routing-system-for-a-php-mvc-application-16f7</guid>
      <description>&lt;h2&gt;
  
  
  You don't want to use a framework and yet you want to get rid of messy URLs and complex routing systems? Maybe I have the solution for you.
&lt;/h2&gt;

&lt;p&gt;Any PHP framework can handle extremely well the routing/dispatching system, but not everyone is interested in a framework to do their job. You came here because you want to do your own routing system, right? Come along, I'll show you my approach to this issue and who knows it will help you to get an ever effective way to do a proper routing system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand what you need to grab to build your function call
&lt;/h2&gt;

&lt;p&gt;There is a superglobal that will help you in this challenge: &lt;em&gt;$&lt;/em&gt;&lt;code&gt;_SERVER&lt;/code&gt;. Just like the PHP documentation says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;$&lt;code&gt;_SERVER&lt;/code&gt;&lt;/em&gt; is an array containing information such as headers, paths, and script locations. The entries in this array are created by the web server. There is no guarantee that every web server will provide any of these; servers may omit some, or provide others not listed here.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.php.net/manual/en/reserved.variables.server.php" rel="noopener noreferrer"&gt;https://www.php.net/manual/en/reserved.variables.server.php&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;PHP warns you about the potential absence of information, but the main one we will use, &lt;code&gt;PATH_INFO&lt;/code&gt;, is very likely to be provided. Even if &lt;code&gt;PATH_INFO&lt;/code&gt; is not there (for example, if no actual path is provided), we can create a default value, say '/'.&lt;/p&gt;

&lt;p&gt;Without any further introduction, let's write some code! &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs.w.org%2Fimages%2Fcore%2Femoji%2F14.0.0%2Fsvg%2F2328.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs.w.org%2Fimages%2Fcore%2Femoji%2F14.0.0%2Fsvg%2F2328.svg" alt="⌨️"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;**Warning:&lt;/em&gt;&lt;em&gt; at the time of this writing I'm using PHP 8.1. Please note that the following code may or may not work in your environment, depending not only on the PHP version but also on your web server.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Get the URI
&lt;/h3&gt;

&lt;p&gt;The first step is to create a function that simply grabs the URI and breaks it into many parts. These parts will represent the controller, method and method parameters (args).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

private static function getURI() : array
{
    $path_info = $_SERVER['PATH_INFO'] ?? '/';
    return explode('/', $path_info);
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So, for a URL like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

http://www.example.com/posts/view/3


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You will get:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$uri[0] = 'posts';
$uri[1] = 'view';
$uri[2] = '3';


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you can already imagine a &lt;em&gt;posts&lt;/em&gt; controller, with a method called &lt;em&gt;view&lt;/em&gt; that receives as an argument &lt;em&gt;post_id&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Process the &lt;em&gt;getURI&lt;/em&gt; information
&lt;/h3&gt;

&lt;p&gt;Let's build an object that returns the controller, method and args (if any):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

private static function processURI() : array
{
    $controllerPart = self::getURI()[0] ?? '';
    $methodPart = self::getURI()[1] ?? '';
    $numParts = count(self::getURI());
    $argsPart = [];
    for ($i = 2; $i &amp;lt; $numParts; $i++) {
        $argsPart[] = self::getURI()[$i] ?? '';
    }

    //Let's create some defaults if the parts are not set
    $controller = !empty($controllerPart) ?
        '\Controllers\\'.$controllerPart.'Controller' :
        '\Controllers\HomeController';

    $method = !empty($methodPart) ?
        $methodPart :
        'index';

    $args = !empty($argsPart) ?
        $argsPart :
        [];

    return [
        'controller' =&amp;gt; $controller,
        'method' =&amp;gt; $method,
        'args' =&amp;gt; $args
    ];
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Bear in mind that you can simplify your use case and write everything on the same function since it's unlikely that we need to call &lt;em&gt;getURI&lt;/em&gt; one more time. I'm separating both for &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle" rel="noopener noreferrer"&gt;Single-responsibility principle&lt;/a&gt;&lt;/strong&gt; (SRP) purposes.&lt;/p&gt;

&lt;p&gt;The controller used here is just an example, with a namespace &lt;em&gt;Controllers&lt;/em&gt;. The common convention is &lt;em&gt;Controllers\SomethingController&lt;/em&gt;, and I like it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Create a function that wraps up and calls the appropriate controller, method and its arguments
&lt;/h3&gt;

&lt;p&gt;This is the funniest part because you already made the dirty job of deconstructing the URI:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public static function contentToRender() : void
{
    $uri = self::processURI();
    if (class_exists($uri['controller'])) {
        $controller = $uri['controller'];
        $method = $uri['method'];
        $args = $uri['args'];
        //Now, the magic
        $args ? $controller::{$method}(...$args) :
            $controller::{$method}();
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;(Those three dots before the &lt;em&gt;$args&lt;/em&gt; array are called &lt;strong&gt;&lt;a href="https://www.php.net/manual/en/migration56.new-features.php" rel="noopener noreferrer"&gt;array unpacking&lt;/a&gt;&lt;/strong&gt;. Basically, PHP will extract the array values and instantiate them as separate variables.)&lt;/p&gt;

&lt;p&gt;But wait! What happened here?&lt;/p&gt;

&lt;p&gt;Let's pick up again our previous example, but with an extra argument:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

http://www.example.com/posts/view/3/excerpt


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this case, we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Controller: &lt;em&gt;\Controllers\PostsController&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Method: &lt;em&gt;view()&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Args: &lt;em&gt;('3', 'excerpt')&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, our call will be: &lt;em&gt;\Controllers\PostsController::view('3', 'excerpt')&lt;/em&gt;. Essentially, the excerpt of the &lt;em&gt;post&lt;/em&gt; with an &lt;em&gt;id&lt;/em&gt; equal to '3'.&lt;/p&gt;

&lt;p&gt;Very simple, yet effective. If no method is passed, we will assume &lt;em&gt;index&lt;/em&gt; as our default method. But beware, the application will throw an error if you don't have any default method called &lt;em&gt;index&lt;/em&gt; and you don't explicitly it either.&lt;/p&gt;

&lt;p&gt;How can we call this?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Route::contentToRender();


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is assuming that we called the class &lt;em&gt;Route&lt;/em&gt;. And please note that we are also assuming that our controller methods are static. If they are not static you have to make a little change to &lt;em&gt;contentToRender()&lt;/em&gt; function.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$args ? $controller::{$method}(...$args) :
            $controller::{$method}();


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You have to write:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$args ? (new $controller)-&amp;gt;{$method}(...$args) :
        (new $controller)-&amp;gt;{$method}();


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I use static methods a lot and I know they are harder to test. Karma will kill me sooner or later for doing that.&lt;/p&gt;

&lt;p&gt;Wrapping up, here is our class &lt;em&gt;Route.php&lt;/em&gt;:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;&amp;lt;?php&lt;/p&gt;

&lt;p&gt;class Route&lt;br&gt;
{&lt;br&gt;
    public static function contentToRender() : void&lt;br&gt;
    {&lt;br&gt;
        $uri = self::processURI();&lt;br&gt;
        if (class_exists($uri['controller'])) {&lt;br&gt;
            $controller = $uri['controller'];&lt;br&gt;
            $method = $uri['method'];&lt;br&gt;
            $args = $uri['args'];&lt;br&gt;
            //Now, the magic&lt;br&gt;
            $args ? $controller::{$method}(...$args) :&lt;br&gt;
                $controller::{$method}();&lt;br&gt;
        }&lt;br&gt;
    }&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static function getURI() : array
{
    $path_info = $_SERVER['PATH_INFO'] ?? '/';
    return explode('/', $path_info);
}

private static function processURI() : array
{
    $controllerPart = self::getURI()[0] ?? '';
    $methodPart = self::getURI()[1] ?? '';
    $numParts = count(self::getURI());
    $argsPart = [];
    for ($i = 2; $i &amp;amp;lt; $numParts; $i++) {
        $argsPart[] = self::getURI()[$i] ?? '';
    }

    //Let's create some defaults if the parts are not set
    $controller = !empty($controllerPart) ?
    '\Controllers\\'.$controllerPart.'Controller' :
    '\Controllers\HomeController';

    $method = !empty($methodPart) ?
        $methodPart :
        'index';

    $args = !empty($argsPart) ?
        $argsPart :
        [];

    return [
        'controller' =&amp;amp;gt; $controller,
        'method' =&amp;amp;gt; $method,
        'args' =&amp;amp;gt; $args
    ];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Do you have another way to make this?&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;I'm pretty sure you do! I'm always into cleaner and shorter code, so if you have any proposals to improve this approach, please let us know in the comments. That way, we, PHP fanboys, can get the PHP awesomeness bar even higher!&lt;/p&gt;

&lt;p&gt;Have a great day!&lt;/p&gt;

</description>
      <category>php</category>
      <category>routing</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Write your first QueryBuilder with PDO and PHP</title>
      <dc:creator>Micael Vinhas</dc:creator>
      <pubDate>Tue, 16 Aug 2022 13:47:00 +0000</pubDate>
      <link>https://forem.com/mvinhas/write-your-first-querybuilder-with-pdo-and-php-o8h</link>
      <guid>https://forem.com/mvinhas/write-your-first-querybuilder-with-pdo-and-php-o8h</guid>
      <description>&lt;p&gt;Take this article as storytelling, where you start with the very basics and then improve your code as you move on.&lt;/p&gt;

&lt;p&gt;Grab a cup of coffee if you didn't do it already.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the importance of writing cleaner queries
&lt;/h2&gt;

&lt;p&gt;Writing the raw SQL is not necessarily hard or inconvenient most of the time, but as soon as your application takes off and goes big, you will have a bunch of long strings with SQL code that simply does not go along with the other PHP code.&lt;/p&gt;

&lt;p&gt;Writing a query builder makes the code much more seamless and readable. Also, you will be less error-prone, because the query building will prepare the query in a consistent way.&lt;/p&gt;

&lt;p&gt;In this article, we will approach SELECT statements.&lt;/p&gt;

&lt;h2&gt;
  
  
  SELECT statements
&lt;/h2&gt;

&lt;p&gt;By the end of this article, your application should run the following query&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT customers.id FROM customers LEFT JOIN persons ON customers.person_id = persons.id WHERE customers.name = 'David' AND persons.id = 1 LIMIT 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(new Select('customers.id'))
-&amp;gt;from('customers LEFT JOIN persons')
-&amp;gt;on(['customers.person_id','=','persons.id'])
-&amp;gt;where(['customers.name', '=', '"David"'])
-&amp;gt;limit(1)-&amp;gt;fetch()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But first, we will cover something much more basic&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM customers WHERE name = 'David' LIMIT 5;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(new Select)-&amp;gt;from('customers')-&amp;gt;where(['name', '=', 'David'])-&amp;gt;limit(5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the above code, we already know a couple of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We have a class called &lt;strong&gt;Select&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  The class has, at least, three methods. They are &lt;em&gt;from&lt;/em&gt;, &lt;em&gt;where&lt;/em&gt; and &lt;em&gt;limit&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  One method should be responsible to make the query. Let's call it &lt;em&gt;fetch&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is enough to write the base class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Select
{
    public function from(string $table) {}
    public function where(array $condition) {}
    public function limit(int $limit = 1) {}
    public function fetch() {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking great, but we are not making any actual query, we are only writing the SQL statement. Making the query itself obliges us to create a PDO Connection (for example).&lt;/p&gt;

&lt;p&gt;If we create this initialization code on the Select class, we have to do it over and over again for any other database operation, like insert or update. So, let's create another class called &lt;strong&gt;Db&lt;/strong&gt; and extend it on &lt;strong&gt;Select&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

use PDO;
use PDOException;

class Db
{
    public static function initialize()
    {
        try {
            return new PDO(
                'mysql:host=localhost;dbname=db',
                'user',
                'password'
            );
        } catch (PDOException $e) {
            die("Could not connect to the database: $e");
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

class Select extends Db
{
    public function from(string $table) {}
    public function where(array $condition) {}
    public function limit(int $limit = 1) {}
    public function fetch() {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good basis to work with.&lt;/p&gt;

&lt;p&gt;Now, we need to create three variables: &lt;em&gt;$from&lt;/em&gt;, &lt;em&gt;$where&lt;/em&gt;, and &lt;em&gt;$limit&lt;/em&gt;. These variables will save the different parts of the query we want to do. There are many more for a SELECT query, but it's wise to start with the basics and then work our way up to create more complex queries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public $from;
public $where;
public $limit;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All declarations are set, time to fill the methods with code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function from(string $table)
{
    $this-&amp;gt;from = "SELECT * FROM $table";
    return $this;
}

public function where(array $condition)
{
    $this-&amp;gt;where = "WHERE $condition[0] $condition[1] $condition[2]";
    return $this;
}

public function limit(int $limit = 0)
{
    $this-&amp;gt;limit = "LIMIT $limit";
    return $this-&amp;gt;fetch();
}

public function fetch()
{
    $sql = implode(' ', (array)$this);
    $db = self::initialize();
    $db-&amp;gt;beginTransaction();
    $query = $db-&amp;gt;prepare($sql);
    $db-&amp;gt;commit();
    $query-&amp;gt;execute();
    return $query-&amp;gt;fetchAll(PDO::FETCH_OBJ);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, a call on index.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

require_once 'Select.php';
require_once 'Db.php';

$query = (new Select)-&amp;gt;from('customers')-&amp;gt;where(['name', '=', 'David'])-&amp;gt;limit(5);

echo "&amp;lt;pre&amp;gt;";print_r($query);"&amp;lt;/pre&amp;gt;";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Array
(
    [0] =&amp;gt; stdClass Object
        (
            [id] =&amp;gt; 3
            [name] =&amp;gt; David
        )

    [1] =&amp;gt; stdClass Object
        (
            [id] =&amp;gt; 4
            [name] =&amp;gt; David
        )

)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have the foundations, but our code is too basic right now. We cannot select a particular field, or make multiple wheres, aside from other constraints.&lt;/p&gt;

&lt;p&gt;I have a couple of ideas to make our Select class richer and more featureful. Use the comments section to throw some more ideas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Select particular fields&lt;/li&gt;
&lt;li&gt;  Multiple &lt;em&gt;wheres&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  Joins&lt;/li&gt;
&lt;li&gt;  Discard the mandatory use of &lt;em&gt;limit&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Select particular fields
&lt;/h3&gt;

&lt;p&gt;In the above example, we already know that the name we want to query is David, so grabbing the &lt;em&gt;id&lt;/em&gt; only should be enough.&lt;/p&gt;

&lt;p&gt;This is the query we want to make:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT id FROM customers WHERE name = 'David' LIMIT 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is a potential approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(new Select('id'))-&amp;gt;from('customers')-&amp;gt;where(['name','=','"David"'])-&amp;gt;limit(5);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are passing &lt;em&gt;id&lt;/em&gt; as a parameter of the class, so we need to implement this code on the constructor.&lt;/p&gt;

&lt;p&gt;(Don't feel lost. I will paste the complete code at the end of this article.)&lt;/p&gt;

&lt;p&gt;On class Select.php:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public $fields;

public function __construct(string $fields = '*')
{
    $this-&amp;gt;fields = "SELECT $fields";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the constructor is now responsible to start the query, we have to adapt our &lt;em&gt;from&lt;/em&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function from(string $table) {
    $this-&amp;gt;from = $table;
    return $this;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest stays exactly the same, and here is the produced result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Array
(
    [0] =&amp;gt; stdClass Object
        (
            [id] =&amp;gt; 3
        )

    [1] =&amp;gt; stdClass Object
        (
            [id] =&amp;gt; 4
        )

)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is exactly want we want.&lt;/p&gt;

&lt;p&gt;Moving on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple &lt;em&gt;wheres&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;You may have noticed that we are passing a unidimensional array to the &lt;em&gt;where&lt;/em&gt; function. So, for the following query...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM customers WHERE name = 'David' AND id = '3' LIMIT 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...how can we write the query builder to accommodate two clauses on &lt;em&gt;where&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;There are a couple of possible solutions, but, I like the CodeIgniter way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(new Select)
-&amp;gt;from('customers')
-&amp;gt;where(['name','=','"David"'],'AND',['id','=','3'])
-&amp;gt;limit(1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not 100% equal to how CodeIgniter implements their &lt;em&gt;where&lt;/em&gt; function, but for this article, I think it's the most comprehensive way.&lt;/p&gt;

&lt;p&gt;We need to use &lt;a href="https://www.php.net/manual/en/migration56.new-features.php"&gt;array unpacking&lt;/a&gt; because we don't know the number of parameters needed. You may only need to use one clause, or twenty.&lt;/p&gt;

&lt;p&gt;Let's try to make it work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function where(...$conditions)
{
    $where[] = 'WHERE';
    foreach ($conditions as $condition) {
        $where[] =
            is_array($condition) ?
            implode(' ', $condition) :
            $condition;
    }
    $this-&amp;gt;where = implode(' ', $where);
    return $this;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Joins
&lt;/h3&gt;

&lt;p&gt;Joins are very useful and usually help us to get everything we want on a single query.&lt;/p&gt;

&lt;p&gt;They will also bring more complexity to our code, but not that much.&lt;/p&gt;

&lt;p&gt;For the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT customers.id FROM customers LEFT JOIN persons ON customers.person_id = persons.id WHERE customers.name = 'David' AND persons.id = 1 LIMIT 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our query builder can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(new Select('customers.id'))
-&amp;gt;from('customers LEFT JOIN persons')
-&amp;gt;on(['customers.person_id','=','persons.id'])
-&amp;gt;where(['customers.name', '=', '"David"'])
-&amp;gt;limit(1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the new function, &lt;em&gt;on&lt;/em&gt;. Notice something familiar? Yes, it is very similar to &lt;em&gt;where&lt;/em&gt;, so why don't we reuse some code?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public $on;

public function where($conditions)
{
    $this-&amp;gt;where = $this-&amp;gt;clause('WHERE', $conditions);
    return $this;
}

public function on($conditions)
{
    $this-&amp;gt;on = $this-&amp;gt;clause('ON', $conditions);
    return $this;
}

public function clause(string $prefix, ...$conditions)
{
    $array[] = $prefix;
    foreach ($conditions as $condition) {
        $array[] = is_array($condition) ?
            implode(' ', $condition) :
            $condition;
    }
    return implode(' ', $array);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One more step and we are done!&lt;/p&gt;

&lt;h3&gt;
  
  
  Discard the mandatory use of &lt;em&gt;limit&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;If we don't call &lt;em&gt;limit&lt;/em&gt;, our query will not be done, ever. This is because we request the &lt;em&gt;fetch&lt;/em&gt; on the &lt;em&gt;limit&lt;/em&gt; function, which is not ideal.&lt;/p&gt;

&lt;p&gt;Why complicate? The solution is in the front of our eyes. We already have a class called &lt;em&gt;fetch&lt;/em&gt;, so why don't we call it?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(new Select('customers.id'))
-&amp;gt;from('customers LEFT JOIN persons')
-&amp;gt;on(['customers.person_id','=','persons.id'])
-&amp;gt;where(['customers.name', '=', '"David"'])
-&amp;gt;limit(1)-&amp;gt;fetch();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You only need to make a tiny change on the &lt;em&gt;limit&lt;/em&gt; function, because we don't want to call &lt;em&gt;fetch&lt;/em&gt; from there anymore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function limit(int $limit = 1) {
    $this-&amp;gt;limit = "LIMIT $limit";
    return $this;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus: orderBy
&lt;/h2&gt;

&lt;p&gt;Since we are using &lt;code&gt;LIMIT 1&lt;/code&gt;, there is no need to use &lt;code&gt;ORDER BY&lt;/code&gt;, but you may need it in the future.&lt;/p&gt;

&lt;p&gt;The solution is very similar to the &lt;code&gt;limit&lt;/code&gt; function, except in this case we have to accept two parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function orderBy(string $field = '', string $order = 'ASC')
{
    if (empty($field)) return $this;
    $this-&amp;gt;orderBy = "ORDER BY $field $order";
    return $this;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;To see this query builder in action, create three files: &lt;strong&gt;index.php&lt;/strong&gt;, &lt;strong&gt;Db.php,&lt;/strong&gt; and &lt;strong&gt;Select.php&lt;/strong&gt;, and then paste the following code:&lt;/p&gt;

&lt;p&gt;Db.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
use PDO;
use PDOException;

class Db
{
    public static function initialize()
    {
        try {
            return new PDO(
                'mysql:host=localhost;dbname=db',
                'user',
                'password'
            );
        } catch (PDOException $e) {
            die("Could not connect to the database: $e");
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

require_once 'Db.php';

class Select extends Db
{
    //Declare the variables in this order
    public $fields;
    public $from;
    public $on;
    public $where;
    public $orderBy;
    public $limit;

    public function __construct(string $fields = '*')
    {
        $this-&amp;gt;fields = "SELECT $fields";
    }

    public function from(string $table) {
        $this-&amp;gt;from = "FROM $table";
        return $this;
    }

    public function where($conditions)
    {
        $this-&amp;gt;where = $this-&amp;gt;clause('WHERE', $conditions);
        return $this;
    }

    public function on($conditions)
    {
        $this-&amp;gt;on = $this-&amp;gt;clause('ON', $conditions);
        return $this;
    }

    public function clause(string $prefix, ...$conditions) : string
    {
        $array[] = $prefix;
        foreach ($conditions as $condition) {
            $array[] = is_array($condition) ?
                implode(' ', $condition) :
                $condition;
        }
        return implode(' ', $array);
    }

    public function orderBy(string $field = '', string $order = 'ASC')
    {
        if (empty($field)) return $this;
        $this-&amp;gt;orderBy = "ORDER BY $field $order";
        return $this;
    }

    public function limit(int $limit = 1) {
        $this-&amp;gt;limit = "LIMIT $limit";
        return $this;
    }

    public function fetch() {
       $sql = implode(' ', (array)$this);
       $db = self::initialize();
       $db-&amp;gt;beginTransaction();
       $query = $db-&amp;gt;prepare($sql);
       $db-&amp;gt;commit();
       $query-&amp;gt;execute();
       return $query-&amp;gt;fetchAll(PDO::FETCH_OBJ);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;index.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

require_once 'Select.php';
require_once 'Db.php';

$query = (new Select('customers.id'))
-&amp;gt;from('customers LEFT JOIN persons')
-&amp;gt;on(['customers.person_id','=','persons.id'])
-&amp;gt;where(['customers.name', '=', '"David"'])
-&amp;gt;limit(1)-&amp;gt;fetch();

echo "&amp;lt;pre&amp;gt;";print_r($query);"&amp;lt;/pre&amp;gt;";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to create the tables &lt;em&gt;customers&lt;/em&gt; and &lt;em&gt;persons&lt;/em&gt;, and, of course, the proper database (in this example: &lt;em&gt;db&lt;/em&gt;). Change the code to suit your data if you want.&lt;/p&gt;

&lt;p&gt;Looking for our GitHub repository? &lt;a href="https://github.com/MVinhas/querybuilder_php_pdo"&gt;Here it is&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Further steps?
&lt;/h2&gt;

&lt;p&gt;There are always things to improve. For example, we can create some error messages to bring more feedback to the user when something is not ok.&lt;/p&gt;

&lt;p&gt;And many more things, like subqueries and unions. If you think that it's a good idea to fill our class with more functionality, let me know in the comments.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

</description>
      <category>pdo</category>
      <category>sql</category>
      <category>php</category>
      <category>querybuilder</category>
    </item>
    <item>
      <title>PHP MVC: the easy way</title>
      <dc:creator>Micael Vinhas</dc:creator>
      <pubDate>Tue, 16 Aug 2022 13:46:43 +0000</pubDate>
      <link>https://forem.com/mvinhas/php-mvc-the-easy-way-4lpd</link>
      <guid>https://forem.com/mvinhas/php-mvc-the-easy-way-4lpd</guid>
      <description>&lt;h2&gt;
  
  
  Get to know MVC better and learn why it's so great.
&lt;/h2&gt;

&lt;p&gt;Tired of getting confused about how to structure your application? You start small and simple but suddenly you have a bunch of files organized almost randomly? You are not alone, and you are not facing a minor problem. An organized application improves code maintainability and reusability and helps other people to cooperate with you.&lt;/p&gt;

&lt;p&gt;In the old times, the usual way of writing applications was by using procedures and global states. We used to write everything on the same file: Infrastructure, Presentation, UI, you name it. Over time, the files got bigger and bigger and we struggled to know where the database operations start and where the UI ends.&lt;/p&gt;

&lt;p&gt;This is where a Separation of Concerns (SoC) comes in handy. By splitting up concepts, the code gets more organized, and you can take it to the next level by creating layers for each concern. You can either find your own way to structure the application or use a proven pattern, like MVC.&lt;/p&gt;

&lt;p&gt;MVC stands for Model-View-Controller. This is a layered architecture, which means that the main goal is to separate different components of an application. There are many more, such as MVVM (Model-view-viewmodel), but this is the most common one. Almost every famous PHP framework uses it by now (Symfony, Yii, Laravel, and CodeIgniter to give some examples).&lt;/p&gt;

&lt;p&gt;By definition, MVC is a paradigm that divides the application into three layers: Model, View, and Controller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmicaelvinhas.com%2Fwp-content%2Fuploads%2F2022%2F04%2Fmvc.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmicaelvinhas.com%2Fwp-content%2Fuploads%2F2022%2F04%2Fmvc.webp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simple MVC diagram as found on Wikipedia&lt;/p&gt;

&lt;p&gt;When writing a form, you are essentially dealing with the three layers. Writing is interacting with the View. Clicking on Save is sending instructions to the Controller, so it can tell the Model to save your data.&lt;/p&gt;

&lt;p&gt;Some examples will be provided as we explain the three layers more deeply.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Model
&lt;/h3&gt;

&lt;p&gt;This layer is responsible to handle all the data. Every action that the user triggers on the application requires some sort of operation on the database. Someone should be responsible to ask the database to change it, and that will be the Model.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?php

namespace Cv\Models;

use Cv\Db;

class Resume
{
    public static function getSections()
    {
        return Db::select(['*'], 'resume_sections');
    }

    public static function getEntries($section)
    {
        return Db::select(
            ['*'],
            'resume_section_entries',
            ['section_id = '.$section-&amp;gt;id]
        );
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There are a couple of extra things worth noting: we are assuming that a class called Db exists and handles querying the database. In that database, two tables, &lt;em&gt;resume_sections&lt;/em&gt;, and &lt;em&gt;resume_section_entries&lt;/em&gt;, represent an entire Resume: &lt;em&gt;resume_sections&lt;/em&gt; divide the Resume and &lt;em&gt;resume_section_entries&lt;/em&gt; describe each Resume section.&lt;/p&gt;

&lt;h3&gt;
  
  
  The View
&lt;/h3&gt;

&lt;p&gt;This layer handles what you see on your screen. It can communicate with both Model and Controller, and its main purpose is to give Model some sort of UI. Think of it as a representation of data for human interaction.&lt;/p&gt;

&lt;p&gt;View: Resume/index.php&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;div class="container"&amp;gt;
    &amp;lt;?php foreach ($data ?? (object)[] as $section) : ?&amp;gt;
        &amp;lt;section class="resume" id="&amp;lt;?= trim(strtolower($section-&amp;gt;title),' ') ?&amp;gt;"&amp;gt;
            &amp;lt;div class="resume-content"&amp;gt;
                &amp;lt;h2 class="mb-3"&amp;gt;&amp;lt;?= $section-&amp;gt;title ?&amp;gt;&amp;lt;/h2&amp;gt;
                &amp;lt;?php foreach ($section-&amp;gt;entries ?? (object)[] as $entry) : ?&amp;gt;
                &amp;lt;div class="mb-3 content"&amp;gt;
                    &amp;lt;div class="content-body"&amp;gt;
                        &amp;lt;h3&amp;gt;&amp;lt;?= $entry-&amp;gt;position ?&amp;gt;&amp;lt;/h3&amp;gt;
                        &amp;lt;div class="subhead mb-1"&amp;gt;&amp;lt;?= $entry-&amp;gt;at ?&amp;gt;&amp;lt;/div&amp;gt;
                        &amp;lt;p&amp;gt;&amp;lt;?= $entry-&amp;gt;description ?&amp;gt;&amp;lt;/p&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div class="content-footer"&amp;gt;
                        &amp;lt;?= $entry-&amp;gt;from ?&amp;gt; - &amp;lt;?= $entry-&amp;gt;to ?? 'Present' ?&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;?php endforeach; ?&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/section&amp;gt;
        &amp;lt;hr class="m-0"&amp;gt;
    &amp;lt;?php endforeach; ?&amp;gt;
&amp;lt;/div&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Nothing fancy here. The view is expecting a $data object to fill the resume on the frontend.&lt;/p&gt;

&lt;p&gt;There is one issue, though. You should separate at all costs PHP from HTML, but this is only achievable with a template engine like &lt;a href="https://twig.symfony.com/" rel="noopener noreferrer"&gt;Twig&lt;/a&gt;. Since we don't want to introduce more concepts here, let's keep Twig out of our examples. We will get back to it in another post.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Controller
&lt;/h3&gt;

&lt;p&gt;The Controller handles organizing and adapting both View and Model. It can receive data from the View and tell the Model what to do, and also it can receive data from the Model and arrange it so it can be comprehended by the user when interacting with the View.&lt;/p&gt;

&lt;p&gt;Controller: ResumeController.php&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?php

namespace Cv\Controllers;

use Cv\Models\Resume;

class ResumeController extends Controller
{
    public static function index()
    {
        $sections = Resume::getSections();
        foreach ($sections as &amp;amp;$section) {
            $section-&amp;gt;entries =
                Resume::getEntries($section);
        }
        return self::view($sections);
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this controller, &lt;em&gt;self::view&lt;/em&gt; is responsible to call the view and pass *$section*s on it.&lt;/p&gt;

&lt;p&gt;But where is the &lt;em&gt;view&lt;/em&gt; function?&lt;/p&gt;

&lt;p&gt;Perhaps you already noticed that this controller extends &lt;em&gt;Controller&lt;/em&gt;. When extending another class, you are inheriting any methods of that class that are not private, and you can use them if you like.&lt;/p&gt;

&lt;p&gt;Let's get to know this Controller to get a grasp of what we are doing here.&lt;/p&gt;

&lt;p&gt;Main Controller: Controller.php&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?php

namespace Cv\Controllers;

class Controller
{
    public static function view(object $data = null)
    {
        include __DIR__.
            '/../Views/'.
            self::path().
            '/'.
            self::file();
    }

    private static function path() : string
    {
        return str_replace(
            'Controller.php',
            '',
            end(
                explode(
                    '/',
                    debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['file']
                )
            )
        );
    }

    private static function file() : string
    {
        return debug_backtrace(
            DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'].'.php';
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This code itself is not essential to understanding this paradigm, but this way you get a rough idea of how a simple MVC application should work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Naming conventions
&lt;/h2&gt;

&lt;p&gt;You should create separate folders for different layers. In this case, Views, Models, and Controllers.&lt;/p&gt;

&lt;p&gt;In the Models folder, every class file should be named by its section. For example Home.php for the homepage-related stuff, Resume.php for everything related to the resume, and so on.&lt;/p&gt;

&lt;p&gt;In the Controllers folder, you should give the classes a similar name to the model classes, but with "Controller" suffix. For example, HomeController.php. Mind that nothing here is mandatory, just a few common practices.&lt;/p&gt;

&lt;p&gt;The view name should match the controller method. So, if you are writing a function called &lt;em&gt;index&lt;/em&gt; for the HomeController, the view should be Views/Home/index.php. This is a great way to understand what that particular View is about. Also, if you need to change its behavior, you already know what method you should change.&lt;/p&gt;

&lt;p&gt;Finally, the application directories should look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

App/
    Models/
        Home.php
        Site.php
        Resume.php
    Controllers/
        HomeController.php
        SiteController.php
        ResumeController.php
    Views/
        Home/
            index.php
        Site/
            index.php
            about.php
        Resume/
            index.php
            edit.php
            delete.php


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, a question. Looking at the above folder structure and respective files, how many methods do ResumeController.php have, and how are they called?&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This type of layered architecture is one of the most used because it's also easier to understand. Once you get used to it, you want to write all your applications using MVC patterns because they will look much more polished and organized. Other types of layered architecture have their merits but MVC represents a great foundation to write better software.&lt;/p&gt;

&lt;p&gt;If you have any further questions please let me and readers know by using the comment section.&lt;/p&gt;




&lt;p&gt;Further reading: &lt;a href="https://leanpub.com/ddd-in-php/read" rel="noopener noreferrer"&gt;Domain-Driven Design in PHP&lt;/a&gt; -- you can get here some MVC examples on the Chapter 2: Architectural Styles.&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>4 great plugins to improve your Wordpress website performance</title>
      <dc:creator>Micael Vinhas</dc:creator>
      <pubDate>Tue, 22 Mar 2022 16:51:30 +0000</pubDate>
      <link>https://forem.com/mvinhas/4-great-plugins-to-improve-your-wordpress-website-performance-48dk</link>
      <guid>https://forem.com/mvinhas/4-great-plugins-to-improve-your-wordpress-website-performance-48dk</guid>
      <description>&lt;p&gt;I created a website called &lt;a href="https://www.poupapilim.com"&gt;Poupa Pilim&lt;/a&gt; (portuguese), which is image heavy since this is mostly supermarket flyers.&lt;/p&gt;

&lt;p&gt;Because of that, and since &lt;a href="https://www.poupapilim.com/category/folhetos/pingo-doce/"&gt;some posts are really huge&lt;/a&gt;, I had to research for some plugins to improve my website performance, which made this beauty score:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ktELZ0yo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6qi6tpstn08vxd5m9f1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ktELZ0yo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6qi6tpstn08vxd5m9f1.png" alt="Image description" width="880" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, let me show you what they are:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Bunny CDN
&lt;/h2&gt;

&lt;p&gt;This is a great CDN, with servers all around the world. Ultra cheap, only 0,01$ per GB of bandwith!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The SEO Framework
&lt;/h2&gt;

&lt;p&gt;You probably know Yoast, but The SEO Framework is more lightweight, simple, unbranded and extremely clear SEO solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. WP Rocket
&lt;/h2&gt;

&lt;p&gt;I bet you already came across with WP Rocket. It is just too great and completely worth the price you pay for it. I use it to minify CSS and JS, defer Javascript and delay Javascript execution, and also to preload fonts and links.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. WP-Optimize - Clean, Compress, Cache
&lt;/h2&gt;

&lt;p&gt;When you install and uninstall plugins, some junk just stays on the database. WP-Optimize will remove that junk and also will optimize your tables. It's free to use.&lt;/p&gt;




&lt;p&gt;On top of this, I make sure that I'm running the latest PHP version (currently PHP 8.1) with some extensions, like APCu and OPCache.&lt;/p&gt;

&lt;p&gt;Also, if your server supports that, enable HTTP2, Deflate and Brotli to get the best performance of your site.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>plugins</category>
      <category>php</category>
    </item>
    <item>
      <title>How to: Apache Userdir with SELinux installed</title>
      <dc:creator>Micael Vinhas</dc:creator>
      <pubDate>Sat, 08 Sep 2018 17:27:19 +0000</pubDate>
      <link>https://forem.com/mvinhas/how-to-apache-userdir-with-selinux-installed-2afk</link>
      <guid>https://forem.com/mvinhas/how-to-apache-userdir-with-selinux-installed-2afk</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bifcoky0xygcf6twe7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bifcoky0xygcf6twe7y.png" alt="SELinux"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the first struggles I had when I started using Fedora as my Linux production environment was to be able to use my &lt;code&gt;/home&lt;/code&gt; folder with Apache and SELinux. Initially I had the habit of linking content from home to &lt;code&gt;/var/www/html&lt;/code&gt;, and then accessing via browser to my projects.&lt;/p&gt;

&lt;p&gt;It turns out that, with SELinux, that’s not an easy task. SELinux’s access control policies, by default, do not allow access to the &lt;code&gt;/home&lt;/code&gt; contents, showing the HTTP 403 Forbidden error. I did a lot of searching over the Internet and I was absolutely silly by the amount of responses that suggested that SELinux should be disabled or put in permissive mode. Disabling things is not a thing I like to do, especially when those things are actually important.&lt;/p&gt;

&lt;p&gt;According to the NSA Security-enhanced Linux Team:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NSA Security-Enhanced Linux is a set of patches to the Linux kernel and utilities to provide a strong, flexible, mandatory access control (MAC) architecture into the major subsystems of the kernel. It provides an enhanced mechanism to enforce the separation of information based on confidentiality and integrity requirements, which allows threats of tampering, and bypassing of application security mechanisms, to be addressed and enables the confinement of damage that can be caused by malicious or flawed applications. It includes a set of sample security policy configuration files designed to meet common, general-purpose security goals.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is, its use helps reduce the likelihood that programs will cause an unwanted behavior on the system, especially if they already have a defect that would allow someone to gain unauthorized access to any part of the system.&lt;/p&gt;

&lt;p&gt;For those who, like me, like to have their projects in their home directory and still want to access these via Apache, how should they proceed? Based on my research, I will introduce you the one that for me is the best solution, and that does not have major security implications.&lt;/p&gt;

&lt;p&gt;NOTE: The process that I’m going to show you was only tested on Fedora 28, but due to the similarities, should work on previous Fedora version as well on Red Hat Linux Enterprise 7.5 and CentOS 7.5.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enable Apache UserDir
&lt;/h1&gt;

&lt;p&gt;This way we can access a specific directory of our /home as our projects directory. Usually it can be accessed as follows:&lt;br&gt;
&lt;code&gt;http://localhost/~user&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Edit userdir.conf file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo vim /etc/httpd/conf.d/userdir.conf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now enable UserDir and specify the folder you want to give access to.&lt;/p&gt;

&lt;p&gt;NOTE: for this tutorial I will use user &lt;code&gt;mvinhas&lt;/code&gt; and folder &lt;code&gt;workspace&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;IfModule mod_userdir.c&amp;gt;
 #
 # UserDir is disabled by default since it can confirm the presence
 # of a username on the system (depending on home directory
 # permissions).
 #
 UserDir enabled mvinhas
#
 # To enable requests to /~user/ to serve the user’s public_html
 # directory, remove the “UserDir disabled” line above, and uncomment
 # the following line instead:
 #
 UserDir workspace
&amp;lt;/IfModule&amp;gt;
&amp;lt;Directory /home/*/workspace&amp;gt;
 AllowOverride FileInfo AuthConfig Limit Indexes
 Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
 Require method GET POST OPTIONS
&amp;lt;/Directory&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will enable UserDir to all users on your computer.&lt;/p&gt;

&lt;p&gt;If you want to specify the users you show keep UserDir disabled and then enable it to the users you want:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
UserDir disabled&lt;br&gt;
UserDir enabled mvinhas user1 user2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note that you can do the opposite, ie. enable UserDir and then deny access to some users:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
UserDir enabled&lt;br&gt;
UserDir disabled mvinhas test1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Restart Apache&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;sudo systemctl start httpd.service&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Change folder permissions to your folder and &lt;code&gt;/home&lt;/code&gt; directory&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;&lt;br&gt;
chmod 711 /home/mvinhas&lt;br&gt;
sudo chown mvinhas:mvinhas /home/mvinhas/workspace&lt;br&gt;
chmod 755 /home/mvinhas/workspace&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Adjust SELinux to enable Apache homedirs&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;&lt;br&gt;
sudo setsebool -P httpd_enable_homedirs true&lt;br&gt;
sudo chcon -R -t httpd_sys_content_t /home/mvinhas/workspace&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now you should be able to use your folder with SELinux enabled!&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpv24ahmkbgpeqqvseg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffpv24ahmkbgpeqqvseg0.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the folder and file SELinux context by doing &lt;code&gt;ls -Z&lt;/code&gt; in the terminal. You can also combine &lt;code&gt;-Z&lt;/code&gt; with the traditional &lt;code&gt;-la&lt;/code&gt; argument, so you can see both SELinux policy and traditional file/folder permissions:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5cq4rm3w5ena7d3h8bh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5cq4rm3w5ena7d3h8bh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, I checked the SELinux status first, showing me that SELinux is in Enforcing mode, the default and recommended mode.&lt;/p&gt;

&lt;p&gt;That’s it. If you have any questions, feel free to ask!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>apache</category>
      <category>fedora</category>
      <category>linuxsecurity</category>
    </item>
  </channel>
</rss>
