Sunday, February 6, 2022

Introducing PHPNews App

Being able to keep oneself updated with latest trends, best practices and news is very crucial especially with the web evolving so rapidly today. This is equally important to become better or what they say modern developer as opposed to obsolete developer. As the technology stack evolves, the client requirements also evolve pushing us as developers to remain abreast of latest stuff as much as we possibly can.

Two of the most common methods to stay up-to-date with latest stuff is to use some RSS/Atom Aggregator or subscription via emails at various sites. These work fine but I was personally overwhelmed by the amount of new updates and posts I used to get, it was kind of hard to keep the track of it all with that many subscriptions from various sources on different technologies. I could have minimized the subscriptions but that wouldn't save the actual purpose.

Therefore being a developer, often times, you come up with your own solution which fits your needs. I wanted just a simple and focused app on just one technology eg PHP that would give me updates from various sources in one central place without bloating me away with too many or stale posts. Since idea was simple, I didn't want to spend too much time on Android so I took the route of using JavaScript to create this app. It turned out there are quite some ways to create Native apps today using one technology that can run across devices and platforms. I found NativeScript quick and easy to get started with although there are other solutions too to make native apps such as ReactNative, Xamarin, Flutter, etc.

Over the weekend, I went on to creating this app called PHPNews and I believe end result is exactly what I wanted as it serves the purpose, here is screenshot:

PHPNews Screen

It collects information from various sources including official blogs of PHP frameworks such as Laravel, Symfony, Zend Framework and CMSs like WordPress and last but not the least our old friend planet-php.net.

Definitely give it a try and also share any suggestions or improvements.

View PHPNews on Android PlayStore

Wednesday, January 10, 2018

Laravel: Automatic Vendor Cleanup Command

When installing composer packages, they come up with lot of useless files and folders such as .git, tests, readme.md and more. When project becomes bigger with many packages, this junk takes considerable disk space. Since I work with Laravel framework most of the time, I created a command that allows me to automatically delete all these junk files whenever I happen to install or update composer packages.

Here is the pattern used by glob function to detect and delete all junk files:

protected $patterns = [
    '.git',
    '.github',
    'test',
    'tests',
    'travis',
    'demo',
    'demos',
    'license',
    'changelog*',
    'contributing*',
    'upgrading*',
    'upgrade*',
    '.idea',
    '.vagrant',
    'readme*',
    '_ide_helper.php',
    '{,.}*.yml',
    '*.yaml',
    '*.md',
    '*.xml',
    '*.log',
    '*.txt',
    '*.dist',
    '*.pdf',
    '*.xls',
    '*.doc',
    '*.docx',
    '*.png',
    '*.gif',
    '*.jpg',
    '*.bmp',
    '*.jpeg',
    '*.ico',
    '.php_cs*',
    '.scrutinizer',
    '.gitignore',
    '.gitattributes',
    '.editorconfig',
    'dockerfile',
    'composer.json',
    'composer.lock',
];

The command itself can be seen here.

To automatically cleanup junk files/folders when installing or updating composer packages in Laravel, @php artisan vendor:cleanup should be added under the post-autoload-dump section in composer.json file. Or we can also trigger it manually anytime by typing php artisan vendor:cleanup --o where --o is optional argument to display verbose output.

If you actually want to be able to use this idea of cleanup of useless files in any PHP project (Laravel or not), you might want to create a composer plugin instead and install it globally that can then work across PHP projects and cleanup useless files from the vendor folder.

If you witness any issue or something missing in the pattern list shown above, please leave your suggestion/improvements in comments. Thanks


Saturday, July 22, 2017

Sockets with PHP and Node

I was looking to implement real time notifications system via sockets without having to use any third party services such as Pusher, etc. I just wanted to be able to send notifications from PHP side to the client and instantly show them on the web application similar to Facebook notifications.

First I came across ratchet library, it worked great but problem emerged when setting it up on secure connection (https) on my host (siteground), tried apache proxy module and everything else told on the internet but to no avail (it seems siteground has problem with ratchet on https) so in the end I had to drop ratchet.

Then I thought of using socket.io with Node+PHP and with my research I came across elephant.io library (though it isn't updated recently) and this one worked wonderfully well both on non-secure and secure protocols allowing us to send and receive messages from PHP with node-based server.

Here are the steps that I followed to get my notification system working.

Install elephant.io

For your PHP application, install elephant.io via composer:

composer require wisembly/elephant.io

Install Node Dependencies

Create a directory in your project root and under it create a file named package.json with these contents:

{
    "name": "elephantIO_example_emitter",
    "version": "3.0.0",
    "main": "server.js",

    "scripts": {
        "start": "supervisor --debug server.js"
    },

    "dependencies": {
        "socket.io": "~1",
        "winston": "*"
    }
}

On newly created directory run command npm install --save. This will install socket.io and logger library.

In same newly created directory, create a file server.js with these contents:

var server     = require('http').createServer(),
    io         = require('socket.io')(server),
    logger     = require('winston'),
    port       = 1337;

// Logger config
logger.remove(logger.transports.Console);
logger.add(logger.transports.Console, { colorize: true, timestamp: true });
logger.info('SocketIO > listening on port ' + port);

io.on('connection', function (socket){
    var nb = 0;

    logger.info('SocketIO > Connected socket ' + socket.id);

    socket.on('broadcast', function (message) {
        ++nb;
        logger.info('ElephantIO broadcast > ' + JSON.stringify(message));

        // send to all connected clients
        io.sockets.emit("broadcast", message);
    });

    socket.on('disconnect', function () {
        logger.info('SocketIO : Received ' + nb + ' messages');
        logger.info('SocketIO > Disconnected socket ' + socket.id);
    });
});

server.listen(port);

Run server.js file through node by typing node server.js, you should see message that server has started on specified port.

Client Side

Put following javascript code in your application's page/footer:

<script src='//cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.4/socket.io.min.js'></script>

<script>
var socket = io.connect('//127.0.0.1:1337');

socket.on('connect', function () {
    console.log('connected');

    socket.on('broadcast', function (data) {
        //console.log(data);
        //socket.emit("broadcast", data);
        alert(data.text);
    });

    socket.on('disconnect', function () {
        console.log('disconnected');
    });
});
</script>

Sending Notification from PHP

Here is how you can send a message to all connected clients:

require __DIR__ . '/vendor/autoload.php';

use ElephantIO\Client;
use ElephantIO\Engine\SocketIO\Version1X;

$client = new Client(new Version1X('//127.0.0.1:1337'));

$client->initialize();
// send message to connected clients
$client->emit('broadcast', ['type' => 'notification', 'text' => 'Hello There!']);
$client->close();

and that's all there is to it.

Installing and Running Node on Production Site

I was on CentOSv6 and I installed node by following this guide. Then I created simple php file that will be run by cron so that node server is automatically started/restarted if it is not running:

$nodePath = 'your node binary path here';
$filePath = 'your server.js file path';
shell_exec($nodePath . ' ' . $filePath);

and then specify that file in cron to run at your specified time intervals.

Important Notes

  • I was having bit of issue getting node path from PHP script where I initially installed it so I copied the nodejs folder to my public_html folder (app's root).
  • On production site, I had to type actual server IP rather than 127.0.0.1 on client side code eg instead of var socket = io.connect('//127.0.0.1:1337');, it has to be var socket = io.connect('//SERVER_IP_HERE:1337');
  • If you are having issue getting it to work on https, check out issues section to fix it.
  • Check out examples folder of elephant.io to know how to send or receive messages both from PHP as well as Javascript.

Sunday, August 28, 2016

From Bad to Good: DI, DIC and Services

In this post, I intend to touch the concepts of:

Even though these terms seems scary at first especially to new-comers but are really easy to understand and help write quality code that is easy to understand and extend. We will take a ^legacy code^ and convert it into object-oriented one by using these principles.

Suppose we have simple application that sends newsletter email to all its subscribers, here is the legacy code:

// file: index.php or could also be considered as Controller file in MVC paradigm

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;

$dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
$pdo = new PDO($dsn);

$mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

$sql = 'SELECT * from subscribers';

foreach ($pdo->query($sql) as $row) {
    $mailer->sendMessage(
        $row['email'],
        'This is the email body',
        $row['name'],
        'info@example.com'
    );
}

Right now above code smells and has these problems:

  • Logic is mixed up, SQL queries, sending emails database configuration is all in one file

To fix this, first instinct is to convert it into class:

class SubscriberMailer
{
    public function sendEmails()
    {
        $dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
        $pdo = new PDO($dsn);

        $mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

        $sql = 'SELECT * from subscribers';

        foreach ($pdo->query($sql) as $row) {
            $mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

This looks good to eye but it has more problems:

  • Logic is still mixed up, SQL queries, sending emails database configuration is all in one file
  • It has hard-coded dependencies (tight-coupling) on PDO and Mailer class, what if we wanted to change Mailer class ?
  • It is hard to unit-test because of tight coupling

Let's try to fix these problems. We can see that this class has dependency on PDO so instead of hard-coding it inside SubscriberMailer class, we can ^pass^ it via its constructor which now makes the class:

class SubscriberMailer
{
    protected $pdo = null;

    public function __construct($pdo)
    {
        $this->pdo = $pdo;
    }

    public function sendEmails()
    {
        $mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

        $sql = 'SELECT * from subscribers';

        foreach ($this->pdo->query($sql) as $row) {
            $mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

This is a bit better, the class doesn't care where PDO objects comes from, it just needs one to operate and you can't instantiate the class without providing one so it makes its intention clear. So this is what is called Dependency Injection, no need to fear even though the term sounded scary initially (read my previous article on more ways of injecting dependencies). Here is how we use above class at this point of the time:

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;
use Demo\Mailer\SubscriberMailer;

$dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
$pdo = new PDO($dsn);

$subscriberMailer = new SubscriberMailer($pdo);
$subscriberMailer->sendEmails();

This is starting to look better compared to first snippet of code. However, we still have a problem in that we have hard-coded smtp config into our class, what if we wanted to change the smtp config without touching the class ? Or what if we had different setup of smtp config for development and production ? Remember a class should be a black-box which simply does its job without editing it again and again, you can only extend it not edit it. So this reasoning hints us that like pdo, we should also pass smtp config via class's constructor and move it from the class itself.

class SubscriberMailer
{
    protected $pdo = null;
    protected $smtpConfig = [];

    public function __construct($pdo, array $smtpConfig)
    {
        $this->pdo = $pdo;
        $this->smtpConfig = $smtpConfig;
    }

    public function sendEmails()
    {
        $mailer = new SmtpMailer(
            $this->smtpConfig['host'],
            $this->smtpConfig['user'],
            $this->smtpConfig['password'],
            $this->smtpConfig['port']
        );

        $sql = 'SELECT * from subscribers';

        foreach ($this->pdo->query($sql) as $row) {
            $mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

Usage:

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;
use Demo\Mailer\SubscriberMailer;

$dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
$pdo = new PDO($dsn);

$subscriberMailer = new SubscriberMailer($pdo, [
   'host' => 'smtp.example.com',
   'user' => 'user',
   'password' => 'password',
   'port' => '465',
]);

$subscriberMailer->sendEmails();

This is better, we can now readily change smtp config in one place and we don't have to touch our class. It still has these problems though:

  • It is tightly coupled to SMTP mailer, what if we wanted to change mailer from smtp to another one like sendmail ?
  • SQL is still written in our class, logic is mixed up, our mail class shouldn't know about users or interact with database, it just needs to send emails !

Hint: The new keyword is considered code-smell, whenever you encounter it, it means it is something you should pass via dependency injection.

So by now we know that to remove hard-coded dependency or tight-coupling, we should pass it instead via dependency injection. So instead of passing mailer config, we should pass mailer object:

class SubscriberMailer
{
    protected $pdo = null;
    protected $mailer = null;

    public function __construct(\PDO $pdo, SmtpMailer $mailer)
    {
        $this->pdo = $pdo;
        $this->mailer = $mailer;
    }

    public function sendEmails()
    {
        $sql = 'SELECT * from subscribers';

        foreach ($this->pdo->query($sql) as $row) {
            $this->mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

Usage:

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;
use Demo\Mailer\SubscriberMailer;

$dsn = 'sqlite:' . __DIR__ . 'database.sqlite';
$pdo = new PDO($dsn);

$mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

$subscriberMailer = new SubscriberMailer($pdo, $mailer);       
$subscriberMailer->sendEmails();

This is better, we removed hard-coded dependency to smtp mailer and notice that we have also type-hinted the PDO and SmtpMailer in the constructor of our class, this is extremely helpful because:

  • Our class makes clear intention that it needs a PDO and SmtpMailer to work properly
  • If somebody passes something other than these two dependencies, they would get clear error message
  • Type-hinting makes our code self-documenting
  • It makes IDE auto-completion

Right now our mailer class knows it needs an instance of SmtpMailer to work and it should have a sendMessage method. Remember, we refactored our code in hope that we might use some other type of mailer like sendmail but problem is that it might not necessarily have the sendMessage method which means we cannot use it. So how do we solve this problem to be able to use some other type of mailer implementation ? Well the answer is to use an interface/contract and use that instead:

// app/Demo/Contracts/MailerInterface.php
interface MailerInterface
{
   public function sendMessage($email, $body, $subject, $from);
}

// app/Demo/Mailer/SmtpMailer.php
use Demo\Contracts\MailerInterface;

class SmtpMailer implements MailerInterface
{
    public function sendMessage($email, $body, $subject, $from) {
        // code to send email
    }
}

// app/Demo/Mailer/SubscriberMailer.php    
class SubscriberMailer
{
    protected $pdo = null;
    protected $mailer = null;

    public function __construct(\PDO $pdo, MailerInterface $mailer)
    {
        $this->pdo = $pdo;
        $this->mailer = $mailer;
    }

    public function sendEmails()
    {
        $sql = 'SELECT * from subscribers';

        foreach ($this->pdo->query($sql) as $row) {
            $this->mailer->sendMessage(
                $row['email'],
                'This is the email body',
                $row['name'],
                'info@example.com'
            );
        }
    }
}

Just like every step that we are performing, this step also has nice advantages:

  • Our SubscriberMailer class is now greatly expandable since it now accepts ANY object that implements MailerInterface that has sendMessage method
  • It documents our code a bit more, it is clear now how an object should be constructed that implements the MailerInterface

All well and good so far. We now see that in our class has SQL to get users. Again it should not care about talking to database, it just needs users' emails to send emails to. To fix this, we need use the Repository Pattern which is essentially a class talking to database to manipulate specific entity, in this case users. So we can pass UserRepository as dependency that has a method to get all users:

// app/Demo/Mailer/SubscriberMailer.php
use Demo\Contracts\MailerInterface;
use Demo\Repositories\UserRepository;

class SubscriberMailer
{
    protected $mailer = null;
    protected $userRepository = null;

    public function __construct(MailerInterface $mailer, UserRepository $userRepository)
    {
        $this->mailer = $mailer;
        $this->userRepository = $userRepository;
    }

    public function sendEmails()
    {
        $users = $this->userRepository->getAll();

        foreach ($users as $user) {
            $this->mailer->sendMessage(
                $user->email,
                'This is the email body',
                $user->name,
                'info@example.com'
            );
        }
    }
}

Usage:

require __DIR__ . 'vendor/autoload.php';

use Demo\Mailer\SmtpMailer;
use Demo\Mailer\SubscriberMailer;
use Demo\Repositories\UserRepository;

$mailer = new SmtpMailer('smtp.example.com', 'user', 'password', '465');

$subscriberMailer = new SubscriberMailer($mailer, new UserRepository);    
$subscriberMailer->sendEmails();

Awesome! our SubscriberMailer class now does not have any mixed-up logic, it is complete black-box whose task is to send emails to provided users. It doesn't need to care about how you pass MailerInterface or UserRepository, it just needs them to operate. It has only one task of sending emails. Not to mention that our class is also easy to be unit-tested. Notice also that we removed PDO as dependency since it is now job of UserRepository to give us the users.

We can now call our class a Service that performs one and only one task without any coupling. If you have heard about Service-Oriented Architecture, this is what it is, a collection of service classes with one and only one responsibility each without any hard-coded dependencies.

At this point of the time, we are all good with our class but one of the downsides of Dependency Injection is that all the complexity of creating and configuring objects is your job. Now this isn't that bad since it happens at one place and gives you the control but it is something which we can still improve.

To do this, we need to leverage what is called Dependency Injection Container (DIC). The job of DIC is to create and configure objects for us. There are many DIC out there for PHP but let's see our modified code using famous Pimple container, here we wrap the dependencies or services into Pimple container. I am not going into details of how to use it, you should refer to its documentation.

// file: container.php

use Demo\Mailer\SmtpMailer;
use Demo\Repositories\UserRepository;
use Pimple\Container;
use Demo\Mailer\SubscriberMailer;

$container = new Pimple();

// container can also hold configs - ideally should be put in separate file...
$container['smtp_config'] = [
   'host' => 'smtp.example.com',
   'user' => 'user',
   'pass' => 'password',
   'port' => '465',
];

$container['mailer'] = $container->share(function(Pimple $container){
   return new SmtpMailer(
      $container['smtp_config']['host'],
      $container['smtp_config']['user'],
      $container['smtp_config']['pass'],
      $container['smtp_config']['port']
   );
});

$container['userRepository'] = $container->share(function(){
   return new UserRepository();
});

$container['subscriberMailer'] = $container->share(function(Pimple $container){
   return new SubscriberMailer($container['mailer'], $container['userRepository']);
});

// file: index.php

require __DIR__ . 'vendor/autoload.php';
require __DIR__ . 'container.php';

$subscriberMailer = $container['subscriberMailer'];
$subscriberMailer->sendEmails();

Notice how clear and concise our index.php code is now compared to initial version.

Using the DIC provides us with these advantages:

  • Wrapping our object creation in container's anonymous function makes object creation lazy which means object isn't created only until needed and if we never reference our SubscriberMailer class, those objects are never created at all saving us memory !
  • Using the container's share method means no matter how many times we need, it will always give us same original object instance. If we need to send many emails, we don't need many instances. This also makes code a bit more faster.
  • All the logic of which objects depend on other objects is abstracted away into container itself, we don't need to worry how they are created or what their dependencies are, we just use our services straight away out of container.
  • If we ever need to change config or something, we only edit it at one place, nobody needs to know about this change.

In conclusion, no matter which framework you use, these principles can be applied to make code which is easy to understand, extend and test.

Popular Posts