Blog Archives

Auto injecting dependencies in PHP objects

I must admit I don’t really know what’s the correct title for this post. Finally I use “Auto injecting dependencies in PHP objects”. I know it isn’t very descriptive. Let me explain it a little bit. This time I want to automate the Hollywood Principle (“Don’t call us, we’ll call you”). The idea is simple. Imagine one “controller”

class Controller
{
    public function hi($name)
    {
        return "Hi $name";
    }
}

We can easily automate the “hi” action

$controller = new Controller();
echo $controller->hi("Gonzalo");

Or maybe if we are building a framework and our class name and action name depends on user-input:

$class = "Controller";
$action = "hi";
$arguments = ['name' => "Gonzalo"];

echo call_user_function_array([new $class, $action], arguments);

But imagine that we want to allow something like that:

class Controller
{
    public function hi($name, Request $request)
    {
        return "Hi $name " .$request->get('surname');
    }
}

Now we need to inject Request object within our action “hi”, but not always. Only when user set a input variable with the type “Request”. Imagine that we also want to allow this kind of injection in the constructor too. We can need to use Reflection to create our instance and to call our action. Sometimes I need to work with custom frameworks and legacy PHP applications. I’ve done it in a couple of projects, but now I want to create a library to automate this operation.

The idea is to use a Dependency Injection Container (Pimple in my example) and retrieve the dependency from container (if it’s available). I cannot use “new” keyword to create the instance and also I cannot call directly the action.

One usage example is:

class Foo
{
    public function hi($name)
    {
        return "Hi $name";
    }
}

class Another
{
    public function bye($name)
    {
        return "Bye $name";
    }
}

class Bar
{
    private $foo;

    public function __construct(Foo $foo, $surname = null)
    {
        $this->foo     = $foo;
        $this->surname = $surname;
    }

    public function hi(Another $another, $name)
    {
        return $this->foo->hi($name . " " . $this->surname) . ' ' . $another->bye($name);
    }
}

$container = new Pimple();
$container['name'] = "Gonzalo2";

$builder = new G\Builder($container);

$bar = $builder->create('Bar', ['surname' => 'Ayuso']);
var_dump($builder->call([$bar, 'hi']));

var_dump($bar->hi(new Another(), 'xxxxx'));

Our library tries to retrieve the dependecy from the DIC. If it cannot do it, it creates the a new instance.
The whole “magic” is in the Builder class. You can see the library in my github account.

Scaling Silex applications

In my humble opinion Silex is great. It’s perfect to create prototypes, but when our application grows up it turns into a mess. That was what I thought until the last month, when I attended to a great talk about Silex with Javier Eguiluz. OK. Scaling Silex it’s not the same than with a Symfony application, but it’s possible.

It’s pretty straightforward to create a Silex application with composer:

{
    "require": {
        "silex/silex": "1.0.*"
    },
    "minimum-stability": "dev"
}

But there’s a better way. We can use the Fabien Potencier’s skeleton. With this skeleton we can organize our code better.

We also can use classes as controllers instead of using a closure with all the code. Igor Wiedler has a great post about this. You can read it here.

Today I’m playing with Silex and I want to show you something. Let’s start:

Probably you know that I’m a big fan of Symfony’s Dependency Injection Container (you can read about it here and here), but Silex uses Pimple. In fact the Silex application extends Pimple Class. My idea is the following one:

In the Igor’s post we can see how to use things like that:

$app->match('/video/{id}', 'Gonzalo123\ApiController::indexAction')->method('GET')->bind('video_info');

My idea is to store this information within a Service Container (we will use Symfony’s DIC). For example here we can see our routes.yml:

routes:
  video_info:
    pattern:  /video/{id}
    controller: Gonzalo123\ApiController::initAction
    requirements:
      _method:  GET

As we can see we need to implement one Extension for the alias “routes”. We only will implement the needed functions for YAML files in this example.

<?php

use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class SilexRouteExtension implements ExtensionInterface
{
    /**
     * Loads a specific configuration.
     *
     * @param array            $config    An array of configuration values
     * @param ContainerBuilder $container A ContainerBuilder instance
     *
     * @throws InvalidArgumentException When provided tag is not defined in this extension
     *
     * @api
     */
    public function load(array $config, ContainerBuilder $container)
    {

    }

    /**
     * Returns the namespace to be used for this extension (XML namespace).
     *
     * @return string The XML namespace
     *
     * @api
     */
    public function getNamespace()
    {

    }

    /**
     * Returns the base path for the XSD files.
     *
     * @return string The XSD base path
     *
     * @api
     */
    public function getXsdValidationBasePath()
    {

    }

    /**
     * Returns the recommended alias to use in XML.
     *
     * This alias is also the mandatory prefix to use when using YAML.
     *
     * @return string The alias
     *
     * @api
     */
    public function getAlias()
    {
        return "routes";

    }
}

And now we only need to prepare the DIC. According to Fabien’s recommendation in his Silex skeleton, we only need to change the src/controllers.php

<?php

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

// Set up container
$container = new ContainerBuilder();
$container->registerExtension(new SilexRouteExtension);
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../config/'));
// load configuration
$loader->load('routes.yml');
$app['container'] = $container;

$app->mount('/api', include 'controllers/myApp.php');

$container->compile();

$app->error(function (\Exception $e, $code) use ($app) {
    if ($app['debug']) {
        return;
    }

    $page = 404 == $code ? '404.html' : '500.html';

    return new Response($app['twig']->render($page, array('code' => $code)), $code);
});

and now we define the config/routes.yml

routes:
  video_info:
    pattern:  /video/{videoId}
    controller: Gonzalo123\ApiController::initAction
    requirements:
      _method:  GET

And finally the magic in our controllers/myApp.php:

<?php

$myApp = $app['controllers_factory'];

foreach ($container->getExtensionConfig('routes')[0] as $name => $route) {
    $controller = $myApp->match($route['pattern'], $route['controller']);
    $controller->method($route['requirements']['_method']);
    $controller->bind($name);
}
return $myApp;

The class for this example is: src/Gonzalo123/ApiController.php

<?php

namespace Gonzalo123;

use Silex\Application;
use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\HttpFoundation\JsonResponse;

class ApiController
{
    public function initAction(Request $request, Application $app)
    {
        return new JsonResponse(array(1, 1, $request->get('id')));
    }
}

As you can see the idea is to use classes as controllers, define them within the service container and build the silex needed code iterating over the configuration. What do you think?

How to configure Symfony’s Service Container to use Twitter API

Keeping on with the series about Symfony’s Services container (another posts here and here), now we will use the service container to use Twitter API from a service.

To use Twitter API we need to handle http requests. I’ve written several post about http request with PHP (example1, example2), but today we will use one amazing library to build clients: Guzzle. Guzzle is amazing. We can easily build a Twitter client with it. There’s one example is its landing page:

<?php
$client = new Client('https://api.twitter.com/{version}', array('version' => '1.1'));
$oauth  = new OauthPlugin(array(
    'consumer_key'    => '***',
    'consumer_secret' => '***',
    'token'           => '***',
    'token_secret'    => '***'
));
$client->addSubscriber($oauth);

echo $client->get('/statuses/user_timeline.json')->send()->getBody();

If we are working within a Symfony2 application or a PHP application that uses the Symfony’s Dependency injection container component you can easily integrate this simple script in the service container. I will show you the way that I use to do it. Let’s start:

The idea is simple. First we include guzzle within our composer.json and execute composer update:

    "require": {
        "guzzle/guzzle":"dev-master"
    }

Then we will create two files, one to store our Twitter credentials and another one to configure the service container:

# twitter.conf.yml
parameters:
  twitter.baseurl: https://api.twitter.com/1.1

  twitter.config:
    consumer_key: ***
    consumer_secret: ***
    token: ***
    token_secret: ***
# twitter.yml
parameters:
  class.guzzle.response: Guzzle\Http\Message\Response
  class.guzzle.client: Guzzle\Http\Client
  class.guzzle.oauthplugin: Guzzle\Plugin\Oauth\OauthPlugin

services:
  guzzle.twitter.client:
    class: %class.guzzle.client%
    arguments: [%twitter.baseurl%]
    calls:
      - [addSubscriber, [@guzzle.twitter.oauthplugin]]

  guzzle.twitter.oauthplugin:
    class: %class.guzzle.oauthplugin%
    arguments: [%twitter.config%]

And finally we include those files in our services.yml:

# services.yml
imports:
- { resource: twitter.conf.yml }
- { resource: twitter.yml }

And that’s all. Now we can use the service without problems:

<?php

namespace Gonzalo123\AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction($name)
    {
        $twitterClient = $this->container->get('guzzle.twitter.client');
        $status = $twitterClient->get('statuses/user_timeline.json')
             ->send()->getBody();

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

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));
    }
}
Follow

Get every new post delivered to your Inbox.

Join 952 other followers