Handling several DBAL Database connections in Symfony2 through the Dependency Injection Container with PHP

(This post is the second part of my previous post: Handling several PDO Database connections in Symfony2 through the Dependency Injection Container with PHP. You can read it here)

OK. We can handle PDOs connections inside a Symfony2 application, but what happens if we prefer DBAL. As we know DBAL is built over PDO and adds a set of “extra” features to our database connection. It’s something like PDO with steroids.

If we read the documentation, we will see how to use DBAL:

<?php
$config = new \Doctrine\DBAL\Configuration();
//..
$connectionParams = array(
    'dbname' => 'mydb',
    'user' => 'user',
    'password' => 'secret',
    'host' => 'localhost',
    'driver' => 'pdo_mysql',
);
$conn = DriverManager::getConnection($connectionParams, $config);

As we can see to obtain a DBAL connection we use a factory method in DriverManager class. We can easily implements it in our service container:

# databases.yml
parameters:
  doctrine.dbal.configuration: Doctrine\DBAL\Configuration
  doctrine.dbal.drivermanager: Doctrine\DBAL\DriverManager

  database.db1:
    driver: pdo_sqlite
    memory: true
  database.db2:
    driver: pdo_pgsql
    dbname: testdb
    user: username
    password: password
    host: 127.0.0.1

services:
  dbal_configuartion:
    class: %doctrine.dbal.configuration%
  db1:
    factory_class: %doctrine.dbal.drivermanager%
    factory_method: getConnection
    arguments: [%database.db1%]
  db2:
      factory_class: %doctrine.dbal.drivermanager%
      factory_method: getConnection
      arguments: [%database.db2%]

But if we run again our example Symfony will throws us one error:

RuntimeException: Please add the class to service “db1” even if it is constructed by a factory since we might need to add method calls based on compile-time checks.

If we use this service container configuration outside Symfony2 application it works (remember we can use Symfony’s Dependency Injection Container outside Symfony application as a component. Example here). But if we want to use it with Symfony2 we need to set the “class”, even here when we only need the static constructor, so we change it to:

# databases.yml
parameters:
  doctrine.dbal.configuration: Doctrine\DBAL\Configuration
  doctrine.dbal.drivermanager: Doctrine\DBAL\DriverManager

  database.db1:
    driver: pdo_sqlite
    memory: true
  database.db2:
    driver: pdo_pgsql
    dbname: testdb
    user: username
    password: password
    host: 127.0.0.1

services:
  dbal_configuartion:
    class: %doctrine.dbal.configuration%
  db1:
    class: %doctrine.dbal.drivermanager%
    factory_class: %doctrine.dbal.drivermanager%
    factory_method: getConnection
    arguments: [%database.db1%]
  db2:
    class: %doctrine.dbal.drivermanager%
    factory_class: %doctrine.dbal.drivermanager%
    factory_method: getConnection
    arguments: [%database.db2%]

And that’s all. We can use DBAL instead of PDO in our database connections.

UPDATE:

After publishing this post someone comment me Doctrine allows us to do it “out of the box” within Symfony with its DoctrineBundle:

https://github.com/doctrine/DoctrineBundle/blob/master/Resources/doc/configuration.rst#doctrine-dbal-configuration

Handling several PDO Database connections in Symfony2 through the Dependency Injection Container with PHP

I’m not a big fan of ORMs, especially in PHP world when all dies at the end of each request. Plain SQL is easy to understand and very powerful. Anyway in PHP we have Doctrine. Doctrine is a amazing project, probably (with permission of Symfony2) the most advanced PHP project, but I normally prefer to work with SQL instead of Doctrine.

Symfony framework is closely coupled to Doctrine and it’s very easy to use the ORM from our applications. But as I said before I prefer not to use it. By the other hand I have another problem. Due to my daily work I need to connect to different databases (not only one) in my applications. In Symfony2 we normally configure the default database in our parameters.yml file:

# parameters.yml
parameters:
    database_driver: pdo_pgsql
    database_host: localhost
    database_port: 5432
    database_name: symfony
    database_user: username
    database_password: password

Ok. If we want to use PDO objects with different databases, we can use something like that:

# parameters.yml
parameters:
  database.db1.dsn: sqlite::memory:
  database.db1.username: username
  database.db1.password: password

  database.db2.dsn: pgsql:host=127.0.0.1;port=5432;dbname=testdb
  database.db2.username: username
  database.db2.password: password

And now create the PDO objects within our code with new \PDO():

$dsn      = $this->container->getParameter('database.db1.dsn');
$username = $this->container->getParameter('database.db1.username');
$password = $this->container->getParameter('database.db1.password')

$pdo = new \PDO($dsn, $username, $password);

It works, but it’s awful. We store the database credentials in the service container but we aren’t using the service container properly. So we can do one small improvement. We will create a new configuration file called databases.yml and we will include this new file within the services.yml:

# services.yml
imports:
- { resource: databases.yml }

And create our databases.yml:

# databases.yml
parameters:
  db.class: Gonzalo123\AppBundle\Db\Db

  database.db1.dsn: sqlite::memory:
  database.db1.username: username
  database.db1.password: password

  database.db2.dsn: pgsql:host=127.0.0.1;port=5432;dbname=testdb
  database.db2.username: username
  database.db2.password: password

services:
  db1:
    class: %db.class%
    calls:
      - [setDsn, [%database.db1.dsn%]]
      - [setUsername, [%database.db1.username%]]
      - [setPassword, [%database.db1.password%]]
  db2:
    class: %db.class%
    calls:
      - [setDsn, [%database.db2.dsn%]]
      - [setUsername, [%database.db2.username%]]
      - [setPassword, [%database.db2.password%]]

As we can see we have created two new services in the dependency injection container called db1 (sqlite in memory) and db2 (one postgreSql database) that use the same class (in this case ‘Gonzalo123\AppBundle\Db\Db’). So we need to create our Db class:

<?php

namespace Gonzalo123\AppBundle\Db;

class Db
{
    private $dsn;
    private $username;
    private $password;

    public function setDsn($dsn)
    {
        $this->dsn = $dsn;
    }

    public function setPassword($password)
    {
        $this->password = $password;
    }

    public function setUsername($username)
    {
        $this->username = $username;
    }

    /** @return \PDO */
    public function getPDO()
    {
        $options = array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION);
        return new \PDO($this->dsn, $this->username, $this->password, $options);
    }
}

And that’s all. Now we can get a new PDO object from our service container with:

$this->container->get('db1')->getPDO();

Better, isn’t it? But it’s still ugly. We need one extra class (Gonzalo123\AppBundle\Db\Db) and this class creates a new instance of PDO object (with getPDO()). Do we really need this class? the answer is no. We can change our service container to:

# databases.yml
parameters:
  pdo.class: PDO
  pdo.attr_errmode: 3
  pdo.erromode_exception: 2
  pdo.options:
    %pdo.attr_errmode%: %pdo.erromode_exception%

  database.db1.dsn: sqlite::memory:
  database.db1.username: username
  database.db1.password: password

  database.db2.dsn: pgsql:host=127.0.0.1;port=5432;dbname=testdb
  database.db2.username: username
  database.db2.password: password

services:
  db1:
    class: %pdo.class%
    arguments:
      - %database.db1.dsn%
      - %database.db1.username%
      - %database.db1.password%
      - %pdo.options%
  db2:
    class: %pdo.class%
    arguments:
      - %database.db2.dsn%
      - %database.db2.username%
      - %database.db2.password%
      - %pdo.options%

Now we don’t need getPDO() and we can get the PDO object directly from service container with:

$this->container->get('db1');

And we can use something like this within our controllers (or maybe better in models):

<?php

namespace Gonzalo123\AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction($name)
    {
        // this code should be out from controller, in a model object.
        // It is only an example
        $pdo = $this->container->get('db1');
        $pdo->exec("CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY, title TEXT, message TEXT)");
        $pdo->exec("INSERT INTO messages(id, title, message) VALUES (1, 'title', 'message')");
        $data = $pdo->query("SELECT * FROM messages")->fetchAll();
        //

        return $this->render('AppBundle:Default:index.html.twig', array('usuario' => $data));
    }
}

How to call shell programs as functions with PHP

I’m a big fan of Symfony’s Process Component. I’ve used intensively this component within a project and I noticed that I needed a wrapper to avoid to write again and again the same code. Suddenly a cool python library came to my head: sh. With python’s sh we can call any program as if it were a function:

from sh import ifconfig
print(ifconfig("wlan0"))

Outputs:

wlan0   Link encap:Ethernet  HWaddr 00:00:00:00:00:00
        inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
        inet6 addr: ffff::ffff:ffff:ffff:fff/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:0 errors:0 dropped:0 overruns:0 frame:0
        TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000
        RX bytes:0 (0 GB)  TX bytes:0 (0 GB)

So I decided to develop something similar in PHP. This library is not exactly the same than python one. Python’s sh allows more cool things such as non-blocking processes, baking, … not available in my PHP one’s, but at least I can call shell programs as functions in a simple way (and that’s was my scope). Let’s start.

One simple example of Process:

use Symfony\Component\Process\Process;

$process = new Process('-latr ~');
$process->setTimeout(3600);
$process->run();

echo $process->getOutput();

With sh library we can do:

use Sh/Sh;

$sh  = new Sh();
echo $sh->ls('-latr ~');

You can check the source code in github, but it’s very simple one. Basically it’s a parser that creates the command line string, and another class that calls to the parser and sends the output to Process component. Whit the magic function __call we can use shell commands as functions.

The command’s arguments can be one string ‘-latr ~’ or one array [‘-latr’, ‘~’]. You can see more example in the unit tests here

Symfony/Process also allows us to get feedback in real time:

use Symfony\Component\Process\Process;

$process = new Process('ls -lsa');
$process->run(function ($type, $buffer) {
    if ('err' === $type) {
        echo 'ERR > '.$buffer;
    } else {
        echo 'OUT > '.$buffer;
    }
});

Sh uses this feature, so we can do things like that:

$sh->tail('/var/log/messages', function ($buffer)  {
    echo $buffer;
});

We can see more examples here:

<?php
error_reporting(-1);
include __DIR__ . '/../vendor/autoload.php';
use Sh\Sh;

echo Sh::factory()->runCommnad('notify-send', ['-t', 5000, 'title', 'HOLA']);
$sh  = new Sh();
echo $sh->ifconfig("eth0");
echo $sh->ls('-latr ~');
echo $sh->ls(['-latr', '~']);
$sh->tail('-f /var/log/apache2/access.log', function ($buffer)  {
    echo $buffer;
});

As I said before the library is in github and also you can use with composer:

require: "gonzalo123/sh": "dev-master"

Updated!

Now Sh library supports chained arguments (baking)

// chainable commands (baking)
$sh->ssh(array('myserver.com', '-p' => 1393))->whoami();
// executes: ssh myserver.com -p 1393 whoami

$sh->ssh(array('myserver.com', '-p' => 1393))->tail(array("/var/log/dumb_daemon.log", 'n' => 100));
// executes: ssh myserver.com -p 1393 tail /var/log/dumb_daemon.log -n 100
});

Managing Windows services with Symfony/Process and PHP

Sometimes I need to stop/start remote Windows services with PHP. It’s quite easy to do it with net commnand. This command is a tool for administration of Samba and remote CIFS servers. It’s pretty straightforward to handle them from Linux command line:

net rpc service --help
Usage:
net rpc service list
    View configured Win32 services
net rpc service start
    Start a service
net rpc service stop
    Stop a service
net rpc service pause
    Pause a service
net rpc service resume
    Resume a service
net rpc service status
    View current status of a service
net rpc service delete
    Deletes a service
net rpc service create
    Creates a service

Today we are going to create a PHP wrapper for this tool. Our NetService library will have two classes: One Parser and one Service class.

The Parser’s responsibility will be create the command line instruction. I will use Behat in the developing process of Parser class. Here we can see the feature file:

Feature: command line parser

  Scenario: net service list
    Given windows server host called "windowshost.com"
    And credentials are "myDomanin/user%password"
    And action is "list"
    Then command line is "net rpc service list -S windowshost.com -U myDomanin/user%password"

  Scenario: net service start
    Given windows server host called "windowshost.com"
    And service name called "ServiceName"
    And credentials are "myDomanin/user%password"
    And action is "start"
    Then command line is "net rpc service start ServiceName -S windowshost.com -U myDomanin/user%password"

  Scenario: net service stop
    Given windows server host called "windowshost.com"
    And service name called "ServiceName"
    And credentials are "myDomanin/user%password"
    And action is "stop"
    Then command line is "net rpc service stop ServiceName -S windowshost.com -U myDomanin/user%password"

  Scenario: net service pause
    Given windows server host called "windowshost.com"
    And service name called "ServiceName"
    And credentials are "myDomanin/user%password"
    And action is "pause"
    Then command line is "net rpc service pause ServiceName -S windowshost.com -U myDomanin/user%password"

  Scenario: net service resume
    Given windows server host called "windowshost.com"
    And service name called "ServiceName"
    And credentials are "myDomanin/user%password"
    And action is "resume"
    Then command line is "net rpc service resume ServiceName -S windowshost.com -U myDomanin/user%password"

  Scenario: net service status
    Given windows server host called "windowshost.com"
    And service name called "ServiceName"
    And credentials are "myDomanin/user%password"
    And action is "status"
    Then command line is "net rpc service status ServiceName -S windowshost.com -U myDomanin/user%password"

The implementation of the feature file:

namespace NetService;

class Parser
{
    private $host;
    private $credentials;

    public function __construct($host, $credentials)
    {
        $this->host        = $host;
        $this->credentials = $credentials;
    }

    public function getCommandLineForAction($action, $service = NULL)
    {
        if (!is_null($service)) $service = " {$service}";
        return "net rpc service {$action}{$service} -S {$this->host} -U {$this->credentials}";
    }
}

and finally our Service class:

namespace NetService;

use Symfony\Component\Process\Process,
    NetService\Parser;

class Service
{
    private $parser;
    private $timeout;

    const START = 'start';
    const STOP = 'stop';
    const STATUS = 'status';
    const LIST_SERVICES = 'list';
    const PAUSE = 'pause';
    const RESUME = 'resume';

    const DEFAULT_TIMEOUT = 3600;

    public function __construct(Parser $parser)
    {
        $this->parser = $parser;
        $this->timeout = self::DEFAULT_TIMEOUT;
    }

    public function start($service)
    {
        return $this->runProcess($this->parser->getCommandLineForAction(self::START, $service));
    }

    public function stop($service)
    {
        return $this->runProcess($this->parser->getCommandLineForAction(self::STOP, $service));
    }

    public function pause($service)
    {
        return $this->runProcess($this->parser->getCommandLineForAction(self::PAUSE, $service));
    }

    public function resume($service)
    {
        return $this->runProcess($this->parser->getCommandLineForAction(self::RESUME, $service));
    }

    public function status($service)
    {
        return $this->runProcess($this->parser->getCommandLineForAction(self::STATUS, $service));
    }

    public function listServices()
    {
        return $this->runProcess($this->parser->getCommandLineForAction(self::LIST_SERVICES));
    }

    public function isRunning($service)
    {
        $status = explode("\n", $this->status($service));
        if (isset($status[0]) && strpos(strtolower($status[0]), "running") !== FALSE) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    public function setTimeout($timeout)
    {
        $this->timeout = $timeout;
    }

    private function runProcess($commandLine)
    {
        $process = new Process($commandLine);
        $process->setTimeout($this->timeout);
        $process->run();

        if (!$process->isSuccessful()) {
            throw new RuntimeException($process->getErrorOutput());
        }

        return $process->getOutput();
    }

    private function parseStatus($status)
    {
        return explode("\n", $status);
    }
}

And that’s all. Now a couple of examples:

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

use NetService\Service,
    NetService\Parser;

$host        = 'windowshost.com';
$serviceName = 'ServiceName';
$credentials = '{domain}/{user}%{password}';

$service = new Service(new Parser($host, $credentials));

if ($service->isRunning($serviceName)) {
    echo "Service is running. Let's stop";
    $service->stop($serviceName);

} else {
    echo "Service isn't running. Let's start";
    $service->start($serviceName);
}

//dumps status output
echo $service->status($serviceName);
include __DIR__ . '/../vendor/autoload.php';

use NetService\Service,
    NetService\Parser;

$host        = 'windowshost.com';
$credentials = '{domain}/{user}%{password}';

$service = new Service(new Parser($host, $credentials));
echo $service->listServices();

You can see the full code in github here. The package is also available for composer at Packaist.

Dependency Injection Containers with PHP. When Pimple is not enough.

Two months ago I wrote an article about Dependency Injection with PHP and Pimple. After the post I was speaking about it with a group of colleagues and someone threw a question:

What happens if your container grows up? Does Pimple scale well?

The answer is not so easy. Pimple is really simple and good for small projects, but it becomes a little mess when we need to scale. Normally when I face a problem like that I like to checkout the Symfony2 code. It usually implements a good solution. There’s something I really like from Symfony2: it’s a brilliant component library and we can use those components within our projects instead of using the full stack framework. So why don’t we only use the Dependency Injection component from SF2 instead Pimple to solve the problem? Let’s start:

We are going to use composer to load our dependencies so we start writing our composer.json file. We want to use yaml files so we need to add “symfony/yaml” and “symfony/config” in addition to “symfony/dependency-injection”:

{
    "require": {
        "symfony/dependency-injection": "dev-master",
        "symfony/yaml": "dev-master",
        "symfony/config": "dev-master"
    },
    "autoload":{
        "psr-0":{
            "":"lib/"
        }
    },
}

Now we can run “composer install” command and we already have our vendors and our autolader properly set.

We are going to build exactly the same example than in the previous post:

<?php
class App
{
    private $proxy;

    public function __construct(Proxy $proxy)
    {
        echo "App::__construct\n";
        $this->proxy = $proxy;
    }

    public function hello()
    {
        return $this->proxy->hello();
    }
}

class Proxy
{
    private $curl;

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

    public function hello()
    {
        echo "Proxy::__construct\n";
        return $this->curl->doGet();
    }
}

class Curl
{
    public function doGet()
    {
        echo "Curl::doGet\n";
        return "Hello";
    }
}

Now we create our file “services.yml” describing our dependency injection container behaviour:

services:
  app:
    class:     App
    arguments: [@Proxy]
  proxy:
    class:     Proxy
    arguments: [@Curl]
  curl:
    class:     Curl

and finally we can build the script:

<?php
include __DIR__ . "/vendor/autoload.php";

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(__DIR__));
$loader->load('services.yml');

$container->get('app')->hello();

IMHO is as simple a Pimple but much more flexible, customizable and it’s also well documented. For example we can split our yaml files into different ones and load them:

<?php
include __DIR__ . "/vendor/autoload.php";

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(__DIR__));
$loader->load('services1.yml');
$loader->load('services2.yml');
$container->get('app')->hello();

An we also can use imports in our yaml files:

imports:
  - { resource: services2.yml }
services:
  app:
    class:     App
    arguments: [@Proxy]

If you don’t like yaml syntax and you prefer XML (I know. It looks insane :)) you can use it, or even programatically with PHP.

What do you think?

Source code in github (see the README to install the vendors)