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.

Integrating WebSockets with PHP applications. Silex and socket.io playing together.

WebSockets are great. We can start a persistent connection from our browser to our server and use this connection to send real time notifications to our users. Normally when we integrate WebSockets with an existing Web application, we need to face with one slight problem. Our Web application runs on a Web server (imagine, for example one Silex application). We can use a login form and ensure all requests are authorized (using a security layer). This problem is solved years ago. We can use Basic HTTP authentification, Digtest authentification, a session based authentication, token based authentificatio, OAuth, … The problem arrives when we add WebSocket server. WebSocket server is another serve. We can use node.js, ruby, or even PHP with Rachet. But how we can ensure that WebSocket server’s requests are also authenticated? We can try to share our authentification provider between both servers, but this solution is quite “exotic”. That was the idea behind my blog post: post some time ago. I’ve been thinkin a lot about it, and also read posts and speak with colleages about this subject. Finally I’m using the following solution. Let me explain it.

Websockets are bi-directional. We can get messages in the browser and send them from browser to server. Basically the solution is to disable the messages from the browser to the server via WebSockets. In fact HTML5 provides another tool to do that called Server Side Events (aka SSE), but SSE aren’t as widely used as WebSockets. Because of that I preffer to use WebSockets (without using the browser-to-server chanel) instead of SSE.

Let’s create a simple Silex application:

class Application extends Silex\Application
{
    use Silex\Application\TwigTrait;
}

$app = new Application();

$app->register(new Silex\Provider\TwigServiceProvider(), array(
    'twig.path' => __DIR__ . '/../views',
));

$app->get('/', function () use ($app) {
    return $app->render('home.twig');
});

$app->run();

And our main template with html file

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<script src="//localhost:8080/socket.io/socket.io.js"></script>
<script>
    var socket = io.connect('//localhost:8080');

    socket.on('id1', function (data) {
        console.log("mensage from websocket: " + data);
    });
</script>
</body>
</html>

Now we have Silex application that connects to a WebSockets server. I will use socket.io to build the WebSocket server:

var CONF = {
        IO: {HOST: '0.0.0.0', PORT: 8080}
    },
    io = require('socket.io').listen(CONF.IO.PORT, CONF.IO.HOST);

Whit this ultra minimal configuration we can connect from Silex application to WebSocket server and our web application will listen to messages marked as’id1′ from the WebSocket server but, how can we do to send messages? As I said before we only rely on Silex application (in this example there isn’t any security layer, but we can use our custom login). The trick is to create a new server within our node.js server. Start this server at localhost and perform a curl request from our Silex Application to our node.js server to send the WebSockets push notifications. The idea is:

  • User clicks a link in our html (generated by our Silex application)
  • This request is a standard Silex request (using our security layer)
  • Then Silex performs a curl request to node.js server.
  • If our Silex application and node.js application are in the same server we will create a new server at localhost. In this example we are going to use Express to do that.
  • Express server will handle requests from our Silex application (not from any other host) and will send WebSocket messages

Now our node.js application will change to

var CONF = {
        IO: {HOST: '0.0.0.0', PORT: 8080},
        EXPRESS: {HOST: 'localhost', PORT: 26300}
    },
    io = require('socket.io').listen(CONF.IO.PORT, CONF.IO.HOST),
    app = require('express')();

app.get('/emit/:id/:message', function (req, res) {
    io.sockets.emit(req.params.id, req.params.message);
    res.json('OK');
});

app.listen(CONF.EXPRESS.PORT, CONF.EXPRESS.HOST);

And our html template will change to (I will use Zepto to perform AJAX requests):

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<ul>
    <li><a href="#" onclick="emit('id1', 'hello')">emit('id1', 'hello')</a></li>
    <li><a href="#" onclick="emit('id1', 'bye')">emit('id1', 'bye')</a></li>
</ul>
<script src="//localhost:8080/socket.io/socket.io.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/zepto/1.1.1/zepto.min.js"></script>
<script>
    var socket = io.connect('//localhost:8080');

    socket.on('id1', function (data) {
        console.log("mensage from websocket: " + data);
    });

    function emit(id, message) {
        $.get('/emit/' + id +  '/' + message);
    }
</script>
</body>
</html>

Now we need to add another route to our Silex application

use Symfony\Component\HttpFoundation\Response;

$app->get('/emit/{id}/{message}', function ($id, $message) use ($app) {
    $s = curl_init();
    curl_setopt($s, CURLOPT_URL, "http://localhost:26300/emit/{$id}/{$message}");
    curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
    $content = curl_exec($s);
    $status = curl_getinfo($s, CURLINFO_HTTP_CODE);
    curl_close($s);

    return new Response($content, $status);
});

And that’s all. Our Request from Silex arrives to WebSocket emmiter using a “secure” layer. OK, now you can said: yes, but anybody can connect to the WebSocket server and listen to ‘id1′ chanel, without any restriction. Yes, it’s true. But here you can use different solutions to ensure privacy. For example you can use a “non-obvious” chanel name based on cryptografic funcions. It’s not 100% secure, but it’s the same security layer than the standard session based security mechanism. If we know the cookie name we can perform a session hijacking attack and gain access to secure areas (without knowing the login credentials). We can generate chanel names like this: 7265cfe8fe3daa4c5069d609a0312dd2 with our Silex Application and send to the browser with an AJAX request.

I’ve created an small screencast to see the prototype in action. (source code in my github account)
In the screencast we can see how to install the prototype from github, install PHP’s vendors and the node js modules. We also can see how websocket works with two browser instances, and how to send messages directly accesing to Express application using localhost interface (and an error when I try to reach to Express server using a different network interface)

What do you think? Do you have another solution?

Playing with HTML5. Building a simple pool of WebWokers

Today I’m playing with the HTML5’s WebWorkers. Since our JavaScript code runs within a single thread in our WebBrowser, heavy scripts can lock the execution of our code. HTML5 gives us one tool called WebWorkers to allow us to run different threads within our Application.

Today I’m playing with one small example (that’s just an experiment). I want to create a pool of WebWebworkers and use them as a simple queue.
The usage of the library is similar than the usage of WebWorkers. The following code shows how to start the pool with 10 instances of our worker “js/worker.js”

    // new worker pool with 10 instances of the worker
    var pool = new WorkerPool('js/worker.js', 10);

    // register callback to worker's onmessage event
    pool.registerOnMessage(function (e) {
        console.log("Received (from worker): ", e.data);
    });

“js/worker.js” is a standard WebWorker. In this example our worker perform XHR request to a API server (in this case one Silex application)

importScripts('ajax.js');

self.addEventListener('message', function (e) {
    var data = e.data;

    switch (data.method) {
        case 'GET':
            getRequest(data.resource, function(xhr) {
                self.postMessage({status: xhr.status, responseText: xhr.responseText});
            });
            break;
    }
}, false);

WebWorkers runs in different scope than a traditional browser application. Not all JavaScript objects are available in the webworker scpope. For example we cannot access to “window” and DOM elements, but we can use XMLHttpRequest. In our experimente we’re going to preform XHR requests from the webworker.

The library creates a queue with the variable number of workers:

var WorkerPool;

WorkerPool = (function () {
    var pool = {};
    var poolIds = [];

    function WorkerPool(worker, numberOfWorkers) {
        this.worker = worker;
        this.numberOfWorkers = numberOfWorkers;

        for (var i = 0; i < this.numberOfWorkers; i++) {
            poolIds.push(i);
            var myWorker = new Worker(worker);

            +function (i) {
                myWorker.addEventListener('message', function (e) {
                    var data = e.data;
                    console.log("Worker #" + i + " finished. status: " + data.status);
                    pool[i].status = true;
                    poolIds.push(i);
                });
            }(i);

            pool[i] = {status: true, worker: myWorker};
        }

        this.getFreeWorkerId = function (callback) {
            if (poolIds.length > 0) {
                return callback(poolIds.pop());
            } else {
                var that = this;
                setTimeout(function () {
                    that.getFreeWorkerId(callback);
                }, 100);
            }
        }
    }

    WorkerPool.prototype.postMessage = function (data) {
        this.getFreeWorkerId(function (workerId) {
            pool[workerId].status = false;
            var worker = pool[workerId].worker;
            console.log("postMessage with worker #" + workerId);
            worker.postMessage(data);
        });
    };

    WorkerPool.prototype.registerOnMessage = function (callback) {
        for (var i = 0; i < this.numberOfWorkers; i++) {
            pool[i].worker.addEventListener('message', callback);
        }
    };

    WorkerPool.prototype.getFreeIds = function () {
        return poolIds;
    };

    return WorkerPool;
})();

The API server is a simple Silex application. This application also enables cross origin (CORS). You can read about it here.

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

$app = new Application();

$app->get('/hello', function () use ($app) {
    error_log("GET /hello");
    sleep(2); // emulate slow process
    return $app->json(['method' => 'GET', 'response' => 'OK']);
});

$app->after(function (Request $request, Response $response) {
    $response->headers->set('Access-Control-Allow-Origin', '*');
});

$app->run();

You can see the whole code in my github account.

Here one small screencast to see the application in action.

Enabling CORS in a RESTFull Silex server, working with a phonegap/cordova applications

This days I’m working with phonegap/cordova projects. I’m using topcoat and AngularJs to build the client side and Silex for the backend. Cordova applications are “diferent” than a common web application. Our client side is normally located inside our mobile device (it’s also possible to use remote webviews). Our cordova application must speak with our backend. The easiest way to perform this operation is to use a REST. AngularJS has a great tool to connect with RESTFull resources. Silex is also great to build RESTFull services. I wrote a couple of posts about it.

With the first request form our AngularJS application (into our android/iphone device) to our Silex application, we will face with CORS. We cannot perform a request from our “local” phonegap/cordova application to our remote WebServer. We cannot do it if we don’t allow it explictily. With Silex it’s pretty straight forward to do it. We can use the event dispatcher and change the request with after handler.

$app->after(function (Request $request, Response $response) {
    $response->headers->set('Access-Control-Allow-Origin', '*');
});

We can do more strict, setting also “Access-Control-Allow-Methods” and “Access-Control-Allow-Headers” headers but only with this header we can work properly with our RESTFull Silex application from our phonegap/cordova application.

How to run a Web Server from a PHP application

Normally we deploy our PHP applications in a webserver (such as apache, nginx, …). I used to have one apache webserver in my personal computer to play with my applications, but from time to now I preffer to use PHP’s built-in webserver for my experiments. It’s really simple. Just run:

php -S 0.0.0.0:8080 

and we’ve got one PHP webserver at our current directory. With another languages (such as node.js, Python) we can start a Web Server from our application. For example with node.js:

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8080, '0.0.0.0');
console.log('Server running at http://0.0.0.0:8080');

With PHP we cannot do it. Sure? That assertion isn’t really true. We can do it. I’ve just create one small library to do it in two different ways. First running the built-in web server and also running one React web server.

I want to share the same interface to start the server. In this implementation we will register one callback to handle incomming requests. This callback will accept a Symfony\Component\HttpFoundation\Request and it will return a Symfony\Component\HttpFoundation\Response. Then we will start our server listening to one port and we will run our callback per Request (a simple implementeation of the reactor pattern)

We will create a static factory to create the server

namespace G\HttpServer;
use React;

class Builder
{
    public static function createBuiltInServer($requestHandler)
    {
        $server = new BuiltInServer();
        $server->registerHandler($requestHandler);

        return $server;
    }

    public static function createReactServer($requestHandler)
    {
        $loop   = React\EventLoop\Factory::create();
        $socket = new React\Socket\Server($loop);

        $server = new ReactServer($loop, $socket);
        $server->registerHandler($requestHandler);

        return $server;
    }
}

Each server (BuiltIn, and React) has its own implementation.

And basically that’s all. We can run a simple webserver with the built-in server

use G\HttpServer\Builder;
use Symfony\Component\HttpFoundation\Request;

Builder::createBuiltInServer(function (Request $request) {
        return "Hello " . $request->get('name');
    })->listen(1337);

Or the same thing but with React

use G\HttpServer\Builder;
use Symfony\Component\HttpFoundation\Request;

Builder::createReactServer(function (Request $request) {
        return "Hello " . $request->get('name');
    })->listen(1337);

As you can see our callback handles one Request and returns one Response (The typical HttpKernel), because of that we also can run one Silex application:
With built-in:

use G\HttpServer\Builder;
use Symfony\Component\HttpFoundation\Request;

$app = new Silex\Application();

$app->get('/', function () {
        return 'Hello';
    });

$app->get('/hello/{name}', function ($name) {
        return 'Hello ' . $name;
    });

Builder::createBuiltInServer(function (Request $request) use ($app) {
        return $app->handle($request);
    })->listen(1337);

And the same with React:

use G\HttpServer\Builder;
use Symfony\Component\HttpFoundation\Request;

$app = new Silex\Application();

$app->get('/', function () {
        return 'Hello';
    });

$app->get('/hello/{name}', function ($name) {
        return 'Hello ' . $name;
    });

Builder::createReactServer(function (Request $request) use ($app) {
        return $app->handle($request);
    })->listen(1337);

As an exercise I also have created one small benchmark (with both implementations) with apache ab running 100 request with a 10 request at the same time. Here you can see the outcomes.

  builtin react
Simple response    
ab -n 100 -c 10 http://localhost:1337/
Time taken for tests 0.878 seconds 0.101 seconds
Requests per second (mean) 113.91 [#/sec] 989.33 [#/sec]
Time per request (mean) 87.791 [ms] 10.108 [ms]
Time per request (mean across all concurrent requests) 8.779 [ms] 1.011 [ms]
Transfer rate 21.02 [Kbytes/sec] 112.07 [Kbytes/sec]
Silex application
ab -n 100 -c 10 http://localhost:1337/
Time taken for tests 2.241 seconds 0.247 seconds
Requests per second (mean) 44.62 [#/sec] 405.29 [#/sec]
Time per request 224.119 [ms] 24.674 [ms]
Time per request (mean across all concurrent requests) 22.412 [ms] 2.467 [ms]
Transfer rate 10.89 [Kbytes/sec] 75.60 [Kbytes/sec]
ab -n 100 -c 10 http://localhost:1337/hello/gonzalo
Time taken for tests 2.183 seconds 0.271 seconds
Requests per second (mean) 45.81 [#/sec] (mean) 369.67 [#/sec]
Time per request (mean) 218.290 [ms] (mean) 27.051 [ms]
Time per request (mean across all concurrent requests) 21.829 [ms] 2.705 [ms]
Transfer rate 11.54 [Kbytes/sec] 71.84 [Kbytes/sec]

Built-in web server is not suitable for production environments, but React would be a useful tool in some cases (maybe not good for running Facebook but good enough for punctual situations).

Library is available at github and also you can use it with composer

Taking photos with a phonegap/cordova application and uploading them to the server.

Last days I’ve working in a phonegap/cordova project. The main purpose of the project was taking photos with the device’s camera and sending them to the server. It’s a simple apache cordova project using the camera plugin. According to the documentation we can upload pictures with the following javascript code:

navigator.camera.getPicture(onSuccess, onFail, { 
    quality: 100,
    destinationType: Camera.DestinationType.DATA_URL
});

function onSuccess(imageData) {
    // here we can upload imageData to the server
}

function onFail(message) {
    alert('Failed because: ' + message);
}

As we can see we our plugin retrieves a base64 encoded version of our image and we can send it to the server, using jQuery for example

function onSuccess(imageData) {
  $.post( "upload.php", {data: imageData}, function(data) {
    alert("Image uploaded!");
  });
}

Our server side is trivial. We only need to read the request variable ‘data’, perform a base64 decode and we have our binary picture ready to be saved.

I test it with an old android smartphone (with a not very good camera) and it’s works, but when I tried to use it with a better android phone (with 8mpx camera) it hangs on and it didn’t work. After property reading the documentation I realized that it isn’t the better way to upload files to the server. It only works if the image file is small. Base64 increases the size of the image and our device can have problems handling the memory. This way Is also slow as hell.

The best way (the way that works, indeed) is, instead of sending the base64 files to the server, to save them into a device’s temporary folder and send them using the file transfer plugin.

var pictureSource;   // picture source
var destinationType; // sets the format of returned value

document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() {
    pictureSource = navigator.camera.PictureSourceType;
    destinationType = navigator.camera.DestinationType;
}

function clearCache() {
    navigator.camera.cleanup();
}

var retries = 0;
function onCapturePhoto(fileURI) {
    var win = function (r) {
        clearCache();
        retries = 0;
        alert('Done!');
    }

    var fail = function (error) {
        if (retries == 0) {
            retries ++
            setTimeout(function() {
                onCapturePhoto(fileURI)
            }, 1000)
        } else {
            retries = 0;
            clearCache();
            alert('Ups. Something wrong happens!');
        }
    }

    var options = new FileUploadOptions();
    options.fileKey = "file";
    options.fileName = fileURI.substr(fileURI.lastIndexOf('/') + 1);
    options.mimeType = "image/jpeg";
    options.params = {}; // if we need to send parameters to the server request
    var ft = new FileTransfer();
    ft.upload(fileURI, encodeURI("http://host/upload"), win, fail, options);
}

function capturePhoto() {
    navigator.camera.getPicture(onCapturePhoto, onFail, {
        quality: 100,
        destinationType: destinationType.FILE_URI
    });
}

function onFail(message) {
    alert('Failed because: ' + message);
}

I just realized that sometimes it fails. It looks like a bug of cordova plugin (I cannot assert it), because of that, if you read my code, you can see that if fp.upload fails I retry it (only once). With this little hack it works like a charm (and it’s also fast).

The server part is pretty straightforward. We only need to handle uploaded files. Here a minimalistic example with php

<?php
move_uploaded_file($_FILES["file"]["tmp_name"], '/path/to/file');

And that’s all. We can easily upload our photos from our smartphone using phonegap/cordova.

Playing with event dispatcher and Silex. Sending logs to a remote server.

Today I continue playing with event dispatcher and Silex. Now I want to send a detailed log of our Kernel events to a remote server. We can do it something similar with Monolog, but I want to implement one working example hacking a little bit the event dispatcher. Basically we’re going to create one Logger class (implementing PSR-3 of course)

namespace G;

use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;

class Logger implements LoggerInterface
{
    private $socket;

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

    function __destruct()
    {
        @fclose($this->socket);
    }

    public function emergency($message, array $context = array())
    {
        $this->sendLog($message, $context, LogLevel::EMERGENCY);
    }

    public function alert($message, array $context = array())
    {
        $this->sendLog($message, $context, LogLevel::ALERT);
    }

    public function critical($message, array $context = array())
    {
        $this->sendLog($message, $context, LogLevel::CRITICAL);
    }

    public function error($message, array $context = array())
    {
        $this->sendLog($message, $context, LogLevel::ERROR);
    }

    public function warning($message, array $context = array())
    {
        $this->sendLog($message, $context, LogLevel::WARNING);
    }

    public function notice($message, array $context = array())
    {
        $this->sendLog($message, $context, LogLevel::NOTICE);
    }

    public function info($message, array $context = array())
    {
        $this->sendLog($message, $context, LogLevel::INFO);
    }

    public function debug($message, array $context = array())
    {
        $this->sendLog($message, $context, LogLevel::DEBUG);
    }

    public function log($level, $message, array $context = array())
    {
        $this->sendLog($message, $context, $level);
    }

    private function sendLog($message, array $context = array(), $level = LogLevel::INFO)
    {
        $data = serialize([$message, $context, $level]);
        @fwrite($this->socket, "{$data}\n");
    }
}

As you can see our Logger class send logs to a remote server, with a socket passed within the constructor.
We also need one Service Provider called LoggerServiceProvider to integrate our Logger instance into our Silex application.

namespace G;

use Silex\Application;
use Silex\ServiceProviderInterface;

class LoggerServiceProvider implements ServiceProviderInterface
{
    private $socket;

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

    public function register(Application $app)
    {
        $app['remoteLogger'] = $app->share(
            function () use ($app) {
                return new Logger($this->socket);
            }
        );
    }

    public function boot(Application $app)
    {
    }
}

And now the last part is our Silex application:

use G\LoggerServiceProvider;
use G\Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel;
use Symfony\Component\HttpKernel\Event;

$app = new Application();
$app->register(new LoggerServiceProvider(stream_socket_client('tcp://localhost:4000')));

$app->on(HttpKernel\KernelEvents::REQUEST, function (Event\GetResponseEvent $event) use ($app) {
        $app->getLogger()->info($event->getName());
    }
);

$app->on(HttpKernel\KernelEvents::CONTROLLER, function (Event\FilterControllerEvent $event) use ($app) {
        $app->getLogger()->info($event->getName());
    }
);

$app->on(HttpKernel\KernelEvents::TERMINATE, function (Event\PostResponseEvent $event) use ($app) {
        $app->getLogger()->info($event->getName());
    }
);

$app->on(HttpKernel\KernelEvents::EXCEPTION, function (Event\GetResponseForExceptionEvent $event) use ($app) {
        $app->getLogger()->critical($event->getException()->getMessage());
    }
);

$app->get('/', function () {
    return 'Hello';
});

$app->run();

As we can see the event dispacher send each event to a remote server (in this example: tcp://localhost:4000). Now we only need a tcp server to handle those sockets. We can use different tools and libraries to do that. In this example we’re going to use React.

use React\EventLoop\Factory;
use React\Socket\Server;

$loop   = Factory::create();
$socket = new Server($loop);

$socket->on('connection', function (\React\Socket\Connection $conn){
    $unique = uniqid();
    $conn->on('data', function ($data) use ($unique) {
            list($message, $context, $level) = \unserialize($data);
            echo date("d/m/Y H:i:s")."::{$level}::{$unique}::{$message}" . PHP_EOL;
        });
});

echo "Socket server listening on port 4000." .PHP_EOL;
echo "You can connect to it by running: telnet localhost 4000" . PHP_EOL;

$socket->listen(4000);
$loop->run();

Now we only need to start our servers:
our silex one

php -S 0.0.0.0:8080 -t www

and the tcp server

php app/server.php

One screencast showing the prototype in action:

You can see the full code in my github account.

Using the event dispatcher in a Silex application

Symfony has one component called The Event Dispatcher. This component is one implementation of Mediator pattern and it’s widely used in modern frameworks, such as Symfony. Silex, as a part of Symfony, also uses this component and we can easily use it in our projects. Let me show you one little example. Imagine one simple route in Silex to create one png file containing one text:

$app->get("/gd/{text}", function($text) {
    $path = "/tmp/qr.png." . uniqid();
    $im = imagecreate(90, 30);
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    return $app->sendFile($path);
});

It works, but there’s one mistake. We need to unlink our temporally file $path, but where? We need do if after “return $app->sendFile($path);” but it’s not possible.

$app->get("/gd/{text}", function($text) {
    $path = "/tmp/qr.png." . uniqid();
    $im = imagecreate(90, 30);
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    return $app->sendFile($path, 200, ['Content-Type' => 'image/png']);;
    unlink($path); // unreachable code
});

We can use BinaryFileResponse instead of the helper function “sendFile”, but there’s one smarter solution: The event dispatcher.

use Symfony\Component\HttpKernel\KernelEvents;

$app->get("/gd/{text}", function($text) use (app) {
    $im = imagecreate(90, 30);
    $path = "/tmp/qr.png." . uniqid();
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    
    $app['dispatcher']->addListener(KernelEvents::TERMINATE, function() use ($path) {
        unlink($path);
    });

    return $app->sendFile($path, 200, ['Content-Type' => 'image/png']);
});

(Updated! thanks to Hakin’s recommendation)
Or even better using Silex’s Filters. In this case we after or finish. In fact those filters are nothing more than an elegant way to speak to the event dispatcher.


$app->get("/gd/{text}", function($text) use (app) {
    $im = imagecreate(90, 30);
    $path = "/tmp/qr.png." . uniqid();
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    
    $app->after(function() use ($path) {
        unlink($path);
    });

    return $app->sendFile($path, 200, ['Content-Type' => 'image/png']);
});

We also can use the generic function to add events to the event listener:

use Symfony\Component\HttpKernel\KernelEvents;

$app->get("/gd/{text}", function($text) use (app) {
    $im = imagecreate(90, 30);
    $path = "/tmp/qr.png." . uniqid();
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    
    $app->on(KernelEvents::TERMINATE, function() use ($path) {
        unlink($path);
    });

    return $app->sendFile($path, 200, ['Content-Type' => 'image/png']);
});

Now our temporally file will be deleted once a response is sent. Life is simpler with event dispatcher :)

Multiple Phonegap Push Notifications in the Android’s status bar

Last month I worked within an Android project using Phonegap, jQuery Mobile and Push Notifications. I also wrote one post explaining how to use PHP to send the server side’s part of the push notifications. Today I want to show one small hack, that I’ve done to change the default behaviour of push notifications. Let me explain it a little bit:

When you use the Push Plugin “out of the box” you will see one message in your Android’s status bar everytime we send one push notification (and you application isn’t running at this moment). If you click on the notification you application will start and you can handle this notification. But if you send more than one notifications to the device, only the last one will be shown on the status bar. This behaviour can be suitable for most situations, but within my application I wanted to see all the notifications in the status bar until I click on one (then all must disappear). If we want to do that we need to hack a little bit our Phonegap application. Let me show you what I’ve done.

Basically we need to change com.plugin.gcm.GCMIntentService file. If we open this Java file we can see that there’s one constant called: NOTIFICATION_ID and a public function called createNotification with something like that:

public static final int NOTIFICATION_ID = 237;
...

public void createNotification(Context context, Bundle extras)
{
    ...
    mNotificationManager.notify((String) appName, NOTIFICATION_ID, mBuilder.build());

}

I’m not a Java expert, but I notice that if I change this function to:

public static final int NOTIFICATION_ID = 237;
public static int MY_NOTIFICATION_ID = 237;
...

public void createNotification(Context context, Bundle extras)
{
    ...
    MY_NOTIFICATION_ID++;
    mNotificationManager.notify((String) appName, MY_NOTIFICATION_ID, mBuilder.build());

}

Now my android device will show multiple notifications, exactly as I need.

If we need to handle properly the way that our notifications are cancelled we also need to modify the public function cancelNotification

public static void cancelNotification(Context context)
{
    NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    //mNotificationManager.cancel((String)getAppName(context), MY_NOTIFICATION_ID);
    mNotificationManager.cancelAll();
    MY_NOTIFICATION_ID = NOTIFICATION_ID;
}

And that’s all. Multiple notifications as I needed.

Sending automated emails with PHP, Swiftmailer and Twig

I’m the one of hosts of a Coding Dojo in my city called Katayunos. Katayunos is the mix of the word Kata (coding kata) and “Desayuno” (breakfast in Spanish). A group of brave programmers meet together one Saturday morning and after having breakfast we pick one coding kata and we practise TDD and pair programming. It’s something difficult to explain to non-geek people (why the hell we wake up early one Saturday morning to do this) but if you are reading this post probably it sounds good:).

My work as host is basically pick the place and encourage people to join to the Coding Dojo. One way of doing this (besides twitter buzz) is take my address book and send one bulk email to all of them inviting to join us. I don’t like this kind of mails. They look like spam, so I prefer to send a personalized email. This email has a common part (the place location, the hour, the event description, …) and the personalized part. I can do it manually, the list isn’t so huge, but definitely that’s not cool. Because of that I have done a little script to perform this operation. I can do a simple PHP script but we are speaking about announcing a event about TDD, SOLID and things like that, so I must use the “right way”. Let’s start.

I manage my list of contacts within a spreadsheet. In this spreadsheet I have the name, the email and a one paragraph with the personalized part to each one of my contact. I can easily export this spreadsheet to a csv document like this:

Peter Parker, spiderman@gmail.com, "Lorem ipsum dolor sit amet, ..."
Clark Kent, superman@gmail.com, "consectetur adipisicing elit, ..."
Juan López Fernández, superlopez@gmail.com, "sed do eiusmod tempor incididunt .."

So first of all I need to parse this file.

class Parser
{
    private $data;

    public function createFromCsvFile($path)
    {
        $handle = fopen($path, "r");
        while (($data = fgetcsv($handle)) !== false) {
            $this->data[] = [
                'name'  => trim($data[0]),
                'email' => trim($data[1]),
                'body'  => isset($data[2]) ? trim($data[2]) : null,
            ];
        }
    }

    public function getData()
    {
        return $this->data;
    }
}

Easy. Now I want to send this parsed array by email. Because of that I will include Swiftmailer in my composer.json file.

My email will also be one template and one personalized part. We will use Twig to manage the template.

"require": {
        "swiftmailer/swiftmailer": "v5.0.2",
        "twig/twig": "v1.13.2",
}

Now we will create a class to wrap the needed code to send emails

class Mailer
{
    private $swiftMailer;
    private $swiftMessage;

    function __construct(Swift_Mailer $swiftMailer, Swift_Message $swiftMessage)
    {
        $this->swiftMailer  = $swiftMailer;
        $this->swiftMessage = $swiftMessage;
    }

    public function sendMessage($to, $body)
    {
        $this->swiftMessage->setTo($to);
        $this->swiftMessage->setBody(strip_tags($body));
        $this->swiftMessage->addPart($body, 'text/html');

        return $this->swiftMailer->send($this->swiftMessage);
    }
}

Our Mailer class sends mails. Our Parser class parses one csv file. Now we need something to join those two classes: the Spammer class. Spammer class will take one parsed array and it will send one by one the mails using Mailer class.

class Spammer
{
    private $twig;
    private $mailer;

    function __construct(Twig_Environment $twig, Mailer $mailer)
    {
        $this->twig       = $twig;
        $this->mailer     = $mailer;
    }

    public function sendEmails($data)
    {
        foreach ($data as $item) {
            $to = $item['email'];
            $this->mailer->sendMessage($to, $this->twig->render('mail.twig', $item));
        }
    }
}

Ok with this three classes I can easily send my emails. This script is a console script and we also want pretty console colours and this kind of stuff. symfony/console to the rescue. But I’ve a problem now. I want to write one message when one mail is sent and another one when something wrong happens. If I want to do that I need to change my Spammer class. But my Spammer class does’t know anything about my console Command. If I inject the console command into my Spammer class I will violate the Demeter law, and that’s a sin. What can we do? Easy: The mediator pattern. We can write one implementation of mediator pattern but we also can use symfony/event-dispatcher, a well done implementation of this pattern. We change our Spammer class to:

use Symfony\Component\EventDispatcher\EventDispatcher;

class Spammer
{
    private $twig;
    private $mailer;
    private $dispatcher;

    function __construct(Twig_Environment $twig, Mailer $mailer, EventDispatcher $dispatcher)
    {
        $this->twig       = $twig;
        $this->mailer     = $mailer;
        $this->dispatcher = $dispatcher;
    }

    public function sendEmails($data)
    {
        foreach ($data as $item) {
            $to = $item['email'];
            try {
                $this->mailer->sendMessage($to, $this->twig->render('mail.twig', $item));
                $this->dispatcher->dispatch(MailEvent::EVENT_MAIL_SENT, new MailEvent\Sent($to));
            } catch (\Exception $e) {
                $this->dispatcher->dispatch(MailEvent::EVENT_SENT_ERROR, new MailEvent\Error($to, $e));
            }
        }
    }
}

Now can easily build of console command class:

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;

class SpamCommand extends Command
{
    private $parser;
    private $dispatcher;

    protected function configure()
    {
        $this->setName('spam:run')
            ->setDescription('Send Emails');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln("Sending mails ...");
        $this->dispatcher->addListener(MailEvent::EVENT_MAIL_SENT, function (MailEvent\Sent $event) use ($output) {
                $output->writeln("<info>Mail sent to</info>: <fg=black;bg=cyan>{$event->getTo()}</fg=black;bg=cyan>");
            }
        );

        $this->dispatcher->addListener(MailEvent::EVENT_SENT_ERROR, function (MailEvent\Error $event) use ($output) {
                $output->writeln("<error>Error sending mail to</error>: <fg=black;bg=cyan>{$event->getTo()}</fg=black;bg=cyan> Error: " . $event->getException()->getMessage());
            }
        );

        $this->spammer->sendEmails($this->parser->getData());
        $output->writeln("End");
    }

    public function setSpammer(Spammer $spammer)
    {
        $this->spammer = $spammer;
    }

    public function setParser(Parser $parser)
    {
        $this->parser = $parser;
    }

    public function setDispatcher(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }
}

With all this parts we can build our script. Our classes are decoupled. That’s good but setting up the dependencies properly can be hard. Because of that we will use symfony/dependency-injection. With symfony DIC we can set up our dependency tree within a yaml file:

Our main services.yml

imports:
  - resource: conf.yml
  - resource: mail.yml
  - resource: twig.yml

parameters:
  base.path: .

services:
  parser:
    class: Parser
    calls:
      - [createFromCsvFile, [%mail.list%]]

  mailer:
    class: Mailer
    arguments: [@swift.mailer, @swift.message]

  spam.command:
    class: SpamCommand
    calls:
      - [setParser, [@parser]]
      - [setDispatcher, [@dispatcher]]
      - [setSpammer, [@spammer]]

  spammer:
    class: Spammer
    arguments: [@twig, @mailer, @dispatcher]

  dispatcher:
    class: Symfony\Component\EventDispatcher\EventDispatcher

I like to separate the configuration files to reuse those files between projects and to make them more readable.

One for twig:

parameters:
  twig.path: %base.path%/templates
  twig.conf:
    auto_reload: true

services:
  twigLoader:
    class: Twig_Loader_Filesystem
    arguments: [%twig.path%]

  twig:
    class: Twig_Environment
    arguments: [@twigLoader, %twig.conf%]

another one for swiftmailer:

services:
  swift.message:
    class: Swift_Message
    calls:
      - [setSubject, [%mail.subject%]]
      - [setFrom, [%mail.from.mail%: %mail.from.name%]]

  swift.transport:
    class: Swift_SmtpTransport
    arguments: [%mail.smtp.host%, %mail.smtp.port%, %mail.smtp.encryption%]
    calls:
      - [setUsername, [%mail.smtp.username%]]
      - [setPassword, [%mail.smtp.password%]]

  swift.mailer:
    class: Swift_Mailer
    arguments: [@swift.transport]

and the last one for the configuration parameters:

parameters:
  mail.do.not.send.mails: false

  mail.list: %base.path%/mailList.csv
  mail.subject: mail subject
  mail.from.name: My Name
  mail.from.mail: my_email@mail.com

  mail.smtp.username: my_smtp_username
  mail.smtp.password: my_smtp_password
  mail.smtp.host: smtp.gmail.com
  mail.smtp.port: 465
  mail.smtp.encryption: ssl

Now we can build our script.

use Symfony\Component\Console\Application;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

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

$container->setParameter('base.path', __DIR__);

$application = new Application();
$application->add($container->get('spam.command'));
$application->run();

n

And that’s all. My colleagues of the next Katayuno will be invited in a “SOLID” way :).
Source code is available in my github account.

BTW: Do you want to organize one Katayuno in your city? It’s very easy. Feel free to contact me for further information.

Follow

Get every new post delivered to your Inbox.

Join 976 other followers