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.

Releasing unmanaged resources (a PHP port from C#’s “using” statement)

Sometimes we work with instances that needs to released even when exceptions happens. Something typical when we work with resources (Files, Database connections, …) Let me show you with an example:

Imagine this class for handling file resources:

class File
{
    private $resource;
    private $logger;

    public function __construct($filename, Loger $logger)
    {
        $this->logger = $logger;
        $this->resource = fopen($filename);
    }

    public function write($string)
    {
        fwrite($this->resource, $string);
    }

    public function close()
    {
        $this->logger->log("file closed")   
        fclose($this->resource);
    }
}

We can use this class:

$file = new File(__DIR__ . "/file.txt", 'w');
$file->write("Hello\n");
// ...
// some other things
// ...
$file->write("Hello\n");
$file->close();

OK. What happens if one exception happens inside “some other things”? Simple answer: close() function isn’t called. This can be a problem. We can face this problem with a try/catch block like this:

try {
    $file->write("Hello\n");
    // ...
    // some other things
    // ...
    $file->write("Hello\n");
    $file->close();
} catch (\Exception $e) {
    $file->close();
}

Or even if we’re using PHP5.5 we can use “finally” keyword

try {
    $file->write("Hello\n");
    // ...
    // some other things
    // ...
    $file->write("Hello\n");
} catch (\Exception $e) {
} finally {
    $file->close();
}

Sometimes I need collaborate with C# projects. C# is a great language. I really like it. It has a really cool feature to solve this problem: the “using” statement. Because of that we are going to build today one small library to implement something similar in PHP.

First we will add G\IDisposable interface to our File class

namespace G;

interface IDisposable
{
    public function dispose();
}

Now our File class looks like this:

use G\IDisposable;

class File implements IDisposable
{
    private $resource;

    public function __construct($filename, $mode)
    {
        $this->resource = fopen($filename, $mode);
    }

    public function write($string)
    {
        fwrite($this->resource, $string);
    }

    public function close()
    {
        fclose($this->resource);
    }

    public function dispose()
    {
        $this->close();
    }
}

And we can use our “using” function in PHP:

using(new File(__DIR__ . "/file.txt", 'w'), function (File $file) {
        $file->write("Hello\n");
        $file->write("Hello\n");
        $file->write("Hello\n");
    });

As we can see we can forget to close() our file instance. “using” will do it for us, even if one exception is triggered inside. We need to take into account that “using” is not a way to handle exceptions. If you want to handle them you need to do it. The only responsibility of “using” is to ensure that dispose() is been called.

We also can use an array of instances (implementing the IDisposable interface of course)

using([new Bar, new Foo], function (Bar $bar, Foo $foo) {
        echo $bar->hello("Gonzalo");
        echo $foo->hello("Gonzalo");
    });

And that’s all. Library is available in github and also you can use it with composer.

Update!
I’ve changed the Example. The first example wasn’t a good one. Now File::close() closes the resource and also write a log. With the first example (without the logger) it wasn’t important to close the resorce (PHP closes it).

Creating QR codes with PHP and Silex

Today we’re going to play with QR codes and how to use them within a Silex application using one Service Provider. First we need a QR code generator. If we find in Packagist we can see various libraries. We are going to use the library: endroid/qrcode.

We are not going to modify endroid/qrcode, because of that we will create a wrapper. This wrapper will receive in the constructor one instance of endroid/qrcode. It’s responsability will be to take one QrCode object and generate a Symfony\Component\HttpFoundation\Response with our QR code and the properly headers. Here you can see the unit tests of our QrWrapper:

use Symfony\Component\HttpFoundation\Response;
use G\QrWrapper;

class QrWrapperTest extends PHPUnit_Framework_TestCase
{
    public function testObjectInit()
    {
        $qrCode = $this->getMockBuilder('Endroid\QrCode\QrCode')
                ->disableOriginalConstructor()
                ->getMock();

        $wrapper = new QrWrapper($qrCode);

        $this->assertInstanceOf('G\QrWrapper', $wrapper);
    }

    public function testGetResponseWithDefaultParameters()
    {
        $qrCode = $this->getMockBuilder('Endroid\QrCode\QrCode')
                ->disableOriginalConstructor()
                ->getMock();

        $qrCode->expects($this->any())->method('get')->will($this->returnValue("hello"));
        $wrapper = new QrWrapper($qrCode);

        $response = $wrapper->getResponse();

        $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
        $this->assertEquals("hello", $response->getContent());
        $this->assertEquals("image/png", $response->headers->get('Content-Type'));
    }

    public function testGetResponseForJpg()
    {
        $qrCode = $this->getMockBuilder('Endroid\QrCode\QrCode')
                ->disableOriginalConstructor()
                ->getMock();

        $qrCode->expects($this->any())->method('get')->will($this->returnValue("hello"));
        $wrapper = new QrWrapper($qrCode);
        $wrapper->setImageType('jpg');

        $response = $wrapper->getResponse();

        $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
        $this->assertEquals("hello", $response->getContent());
        $this->assertEquals("image/jpeg", $response->headers->get('Content-Type'));
    }

    public function testGetResponseForJpeg()
    {
        $qrCode = $this->getMockBuilder('Endroid\QrCode\QrCode')
                ->disableOriginalConstructor()
                ->getMock();

        $qrCode->expects($this->any())->method('get')->will($this->returnValue("hello"));
        $wrapper = new QrWrapper($qrCode);
        $wrapper->setImageType('jpeg');

        $response = $wrapper->getResponse();

        $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
        $this->assertEquals("hello", $response->getContent());
        $this->assertEquals("image/jpeg", $response->headers->get('Content-Type'));
    }

    public function testReusingResponse()
    {
        $qrCode = $this->getMockBuilder('Endroid\QrCode\QrCode')
                ->disableOriginalConstructor()
                ->getMock();

        $qrCode->expects($this->any())->method('get')->will($this->returnValue("hello"));
        $wrapper = new QrWrapper($qrCode);

        $response = new Response('foo');
        $response->headers->set('xxx', 'gonzalo');

        $response = $wrapper->getResponse($response);

        $this->assertEquals("hello", $response->getContent());
        $this->assertEquals("image/png", $response->headers->get('Content-Type'));
        $this->assertEquals("gonzalo", $response->headers->get('xxx'));
    }
}

Now we will create the ServiceProvider. We only need to implement ServiceProviderInterface

use Silex\Application;
use Silex\ServiceProviderInterface;
use Endroid\QrCode\QrCode;

class QrServiceProvider implements ServiceProviderInterface
{
    public function register(Application $app)
    {
        $app['qrCode'] = $app->protect(function ($text, $size = null) use ($app) {
            $default = $app['qr.defaults'];

            $qr = new QrWrapper(new QrCode());
            $qr->setText($text);
            $qr->setPadding($default['padding']);
            $qr->setSize(is_null($size) ? $default['size'] : $size);
            $qr->setImageType($default['imageType']);

            return $qr;
        });
    }

    public function boot(Application $app)
    {
    }
}

And that’s all. Now we can use our service provider within one Silex Application:

use Silex\Application;
use G\QrServiceProvider;

$app = new Application();

$app->register(new QrServiceProvider(), [
    'qr.defaults' => [
        'padding'   => 5, // default: 0
        'size'      => 200,
        'imageType' => 'png', // png, gif, jpeg, wbmp (default: png)
    ]
]);

$app->get("/qr/base64/{text}", function($text) use ($app) {
    return $app['qrCode'](base64_decode($text))->getResponse();
});

$app->get("/qr/{text}", function($text) use ($app) {
    return $app['qrCode']($text)->getResponse();
});

$app->run();

You can fetch the full code in github and also use it with composer

Building a BDD framework with PHP

Do you know Jasmine, the BDD framework for JavaScript? This holidays I was looking for something like that in PHP and I didn’t found anything similar (please let me know if I’m wrong) (now I know a few of them thanks to Dave’s comment) . Because of that, and as an exercise, I hack a little bit building something similar for PHP.

I want to write as less code as I can (it’s only a proof of concept), so I will reuse the assertion framework or PHPUnit. As I’ve seen when studying Behat, we can use the assertion part as standalone functions. We only need to include vendor/phpunit/phpunit/PHPUnit/Framework/Assert/Functions.php file

Here you can see one example.

class StringCalculator
{
    public function add($string)
    {
        return (int)array_sum(explode(",", $string));
    }
}

$stringCalculator = new StringCalculator;

describe("add mull returns zero", function () use ($stringCalculator) {
        assertEquals(null, $stringCalculator->add(""));
    });

describe("1,1 should return 2", function () use ($stringCalculator) {
        assertEquals(2, $stringCalculator->add("1,1"));
    });

We also can use something similar than DataProvider in PHPUnit:

describe("add number returns number", function ($expected, $actual, $message) use ($stringCalculator) {
        assertEquals($expected, $stringCalculator->add($actual), $message);
    }, [
        ['expected' => 1, 'actual' => "1", 'message' => 'add 1'],
        ['expected' => 2, 'actual' => "2", 'message' => 'add 1'],
        ['expected' => 10, 'actual' => "10", 'message' => 'add 10'],
    ]);

And if we need mocks we can use Mockery, for example:

class Temperature
{

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

    public function average()
    {
        $total = 0;
        for ($i=0;$i<3;$i++) {
            $total += $this->_service->readTemp();
        }
        return $total/3;
    }
}

$service = m::mock('service');

describe("testing mocks with mockery", function() use ($service) {
        $service->shouldReceive('readTemp')->andReturn(11, 12, 13);
        $temperature = new Temperature($service);
        assertEquals(12, $temperature->average(), "dummy message");
    });

I’ve created an small console application to run the test suites using symfony/console and symfony/finder components. We can run it with:

php ./bin/console.php texter:run ./tests

Beware because this library is a proof of concept. There’re a lot of remaining things. What do you think?

Source code at github

Sending Android Push Notifications from PHP to phonegap applications

Last days I’ve been working within a Phonegap project for Android devices using Push Notifications. The idea is simple. We need to use the Push Notification Plugin for Android. First we need to register the Google Cloud Messaging for Android service at Google’s console, and then we can send Push notifications to our Android device.

The Push Notification plugin provides a simple example to send notifications using Ruby. Normally my backend is built with PHP (and sometimes Python) so instead of using the ruby script we are going to build a simple PHP script to send Push Notifications.

The script is very simple

<?php
$apiKey = "myApiKey";
$regId = "device reg ID";

$pusher = new AndroidPusher\Pusher($apiKey);
$pusher->notify($regId, "Hola");

print_r($pusher->getOutputAsArray());

And the whole library you can see here:

<?php
namespace AndroidPusher;

class Pusher
{
    const GOOGLE_GCM_URL = 'https://android.googleapis.com/gcm/send';

    private $apiKey;
    private $proxy;
    private $output;

    public function __construct($apiKey, $proxy = null)
    {
        $this->apiKey = $apiKey;
        $this->proxy  = $proxy;
    }

    /**
     * @param string|array $regIds
     * @param string $data
     * @throws \Exception
     */
    public function notify($regIds, $data)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, self::GOOGLE_GCM_URL);
        if (!is_null($this->proxy)) {
            curl_setopt($ch, CURLOPT_PROXY, $this->proxy);
        }
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $this->getHeaders());
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $this->getPostFields($regIds, $data));

        $result = curl_exec($ch);
        if ($result === false) {
            throw new \Exception(curl_error($ch));
        }

        curl_close($ch);

        $this->output = $result;
    }

    /**
     * @return array
     */
    public function getOutputAsArray()
    {
        return json_decode($this->output, true);
    }

    /**
     * @return object
     */
    public function getOutputAsObject()
    {
        return json_decode($this->output);
    }

    private function getHeaders()
    {
        return [
            'Authorization: key=' . $this->apiKey,
            'Content-Type: application/json'
        ];
    }

    private function getPostFields($regIds, $data)
    {
        $fields = [
            'registration_ids' => is_string($regIds) ? [$regIds] : $regIds,
            'data'             => is_string($data) ? ['message' => $data] : $data,
        ];

        return json_encode($fields, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);
    }
}

Maybe we could improve the library with a parser of google’s ouptuput, basically because we need to handle this output to notice if the user has uninstalled the app (and we need the remove his reg-id from our database), but at least now it cover all my needs. You can see the code at github

Bundles in Silex using Stack

In the last Desymfony conference I was speaking with Luis Cordova and he introduced me “Stack” (I must admit Stack was in my to-study-list but only marked as favorite). The idea behind Stack is really cool. (In fact every project where Igor Wiedler appears is brilliant, even the chicken one :)).

Nowadays almost every modern framework/applications implements HttpKernelInterface (Symfony, Laravel, Drupal, Silex, Yolo and even the framework that I’m working in ;)) and we can build complex applications mixing different components and decorate our applications with an elegant syntax.

The first thing than come to my mind after studying Stack is to join different Silex applications in a similar way than Symfony (the full stack framework) uses bundles. And the best part of this idea is that it’s pretty straightforward. Let me show you one example:

Imagine that we’re working with one application with a blog and one API. In this case our blog and our API are Silex applications (but they can be one Symfony application and one Silex application for example).

That’s our API application:

use Silex\Application;

$app = new Application();
$app->get('/', function () {
        return "Hello from API";
    });

$app->run();

And here our blog application:

use Silex\Application;

$app = new Application();
$app->get('/', function () {
        return "Hello from Blog";
    });

$app->run();

We can organize our application using mounted controllers or even using RouteCollections but today we’re going to use Stack and it’s cool url-map.

First we are going to create our base application. To do this we’re going to implement the simplest Kernel in the world, that’s answers with “Hello” to every request:

use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class MyKernel implements HttpKernelInterface
{
    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
    {
        return new Response("Hello");
    }
}

Stack needs HttpKernelInterface and Silex\Application implements this interface, so we can change our Silex applications to return the instance instead to run the application:

// app/api.php
use Silex\Application;

$app = new Application();
$app->get('/', function () {
        return "Hello from API";
    });

return $app;
// app/blog.php
use Silex\Application;

$app = new Application();
$app->get('/', function () {
        return "Hello from API";
    });

return $app;

And now we will attach those two Silex applications to our Kernel:

use Symfony\Component\HttpFoundation\Request;

$app = (new Stack\Builder())
    ->push('Stack\UrlMap', [
            "/blog" => include __DIR__ . '/app/blog.php',
            "/api" => include __DIR__ . '/app/api.php'
        ])->resolve(new MyKernel());

$request = Request::createFromGlobals();

$response = $app->handle($request);
$response->send();

$app->terminate($request, $response);

And that’s all. I don’t know what you think but with Stack one big window just opened in my mind. Cool, isn’t it?

You can see this working example in my github

Dynamic routes with AngularJS and Silex

These days I’m playing with AngularJS. Today I want to experiment with dynamic routes. Let me show your an example. Imagine a simple route configuration:

$routeProvider.when('/page/page1', {templateUrl: 'partials/page1.html', controller: Controller1});
$routeProvider.when('/page/page2', {templateUrl: 'partials/page2.html', controller: Controller2});
$routeProvider.when('/page/page3', {templateUrl: 'partials/page3.html', controller: Controller3});

It’s very simple but: What happens if our application is big and it grows fast? We need to add new lines and reload the browser.
With AngularJS we can add paramenters to the routes:

$routeProvider.when('/page/:page', {templateUrl: 'partials/page.html', controller: Controller});

Now we don’t need to add new routes but what can we do with the partials? After browse the web and stack overflow finally I found this solution:

.when('/page/:page', {template: '<div ng-include="templateUrl">Loading...</div>', controller: DynamicController})

And now we need to define our DynamicController and load there our needed partial:

function DynamicController($scope, $routeParams) {
    var unique = (new Date()).getTime();
    $scope.templateUrl = '/api/pages/' + $routeParams.page + '?unique=' + unique;
}

We can load our partial as a static file but in this example I’m using a Silex backend to provide my partials.

<?php
require_once __DIR__ . '/../../vendor/autoload.php';

use Silex\Application;
use Symfony\Component\HttpFoundation\Response;
$app          = new Application();
$app['debug'] = true;

$app->register(new Silex\Provider\TwigServiceProvider(), [
    'twig.path'    =>  __DIR__.'/../../views',
    'twig.options' => [
       'cache'       => __DIR__ . '/../../cache',
       'auto_reload' => true
    ]
]);

$app->before(function() use ($app){
    $app['twig']->setLexer( new Twig_Lexer($app['twig'], [
        'tag_comment'   => ['[#', '#]'],
        'tag_block'     => ['[%', '%]'],
        'tag_variable'  => ['[[', ']]'],
        'interpolation' => ['#[', ']'],
    ]));
});

$app->get('/pages/{name}', function($name) use ($app){
    return $app['twig']->render('hello.html.twig', ['name' => $name]);
});

$app->get('/pages/js/{name}', function($name) use ($app){
    $response = new Response($app['twig']->render('hello.js', ['name' => $name]));
    $response->headers->set("Content-Type", 'application/javascript');

    return $response;
});

$app->run();

As you can see we need to use one small hack to use twig and AngularJS together. They aren’t good friends with the default configuration. Both uses the same syntax ‘{{ expresion }}’. Because of that we will change Twig’s default behaviour within a middleware.

And basically that’s all. You can see a working example in my github account using Booststrap and UI Booststrap

Talk about Dependency Injection and Dependency Injection Containers at the deSymfony 2013 conference

The last week I attend to deSymfony conference. This year the conference was in Madrid and I collaborate as speaker with a talk about Dependency Injection and Dependency Injection Containers in PHP. It was a great experience. 400 attendees, two tracks, Fabien Potencier’s key-note and a brilliant organization could be one fast summary. We also could enjoy with good talks especially (in my humble opinion) one great talk about Advanced Silex with Javier Egiluz (please Javier write a book about Silex soon :) ). A good place to put the real face to colleagues and to know to the most important people at the PHP/Symfony community in Spain. Nice talks (and beers too) with people from Zaragoza, Extremadura, Valladolid, Valencia, Barcelona, with the people of Symfony-Madrid …

As I said before I participated as speaker with one talk about Dependencies, Containers and SOLID principles. Here you can see the slides of the talk.

The organization will publish soon the video with the talk (in Spanish). And here a couple of pictures of the talk.

desymfony2013.gonzalo123

2013-06-23 17.20.40

And that’s all. Thanks to the organization, the sponsors and of course to all the people who choose to attend to my talk one saturday at 9:30 AM. Say cheese …

desymfony2013.gonzalo123.people

Working with jQuery and Silex as RestFull Resource provider

The previous post was about how to use AngularJS resources with Silex. AngularJS is great and when I need to switch back to jQuery it looks like I go back 10 years in web development, but business is business and I need to live with jQuery too. Because of that this post is about how to use the Silex RestFull resources from the previous post, now with jQuery. Let’s start:

We’re going to write a simple javascript object to handle the RestFull resource using jQuery:

var Resource = (function (jQuery) {
    function Resource(url) {
        this.url = url;
    }

    Resource.prototype.query = function (parameters) {
        return jQuery.getJSON(this.url, parameters || {});
    };

    Resource.prototype.get = function (id, parameters) {
        return jQuery.getJSON(this.url + '/' + id, parameters || {});
    };

    Resource.prototype.remove = function (id, parameters) {
        return jQuery.ajax({
            url:this.url + '/' + id,
            xhrFields:JSON.stringify(parameters || {}),
            type:'DELETE',
            dataType:'json'
        });
    };

    Resource.prototype.update = function (id, parameters) {
        return jQuery.post(this.url + '/' + id, JSON.stringify(parameters || {}), 'json');
    };

    Resource.prototype.create = function (parameters) {
        return jQuery.post(this.url, JSON.stringify(parameters || {}), 'json');
    };

    return Resource;
})(jQuery);

As you can see the library returns jQuery ajax promises, so we can use done() and error() callbacks to work with the server’s data.

Here our application example:

var host = document.location.protocol + '//' + document.location.host;
var resource = new Resource(host + '/api/message/resource');

resource.create({ id: 10, author: 'myname', message: 'hola'}).done(function (data) {
    console.log("create element", data);
});

resource.query().done(function (data) {
   console.log("query all", data);
});

resource.update(10, {message: 'hi'}).done(function (data) {
    console.log("update element 1", data);
});

resource.get(10).done(function (data) {
    console.log("get element 1", data);
});

resource.remove(10).done(function (data) {
    console.log("remove element 1", data);
});

resource.query().done(function (data) {
    console.log("query all", data);
});

And that’s all. You can get the full code of the example from my github account

Working with AngularJS and Silex as Resource provider

This days I’m playing with AngularJS. Angular is a great framework when we’re building complex front-end applications with JavaScript. And the best part is that it’s very simple to understand (and I like simple things indeed). Today we are going to play with Resources. Resources are great when we need to use RestFull resources from the server. In this example we’re going to use Silex in the backend. Let’s start.

First of all we must realize that resources aren’t included in the main AngularJS js file and we need to include angular-resource.js (it comes with Angular package). We don’t really need resources. We can create our http services with AngularJS without using this extra js file but it provides a very clean abstraction (at least for me) and I like it.

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular-resource.min.js"></script>

We’re going to create a simple application with CRUD operations in the table. In the example we will use one simple SqlLite database (included in the github repository)

CREATE TABLE main.messages (
  id INTEGER PRIMARY KEY  NOT NULL ,
  author VARCHAR NOT NULL ,
  message VARCHAR NOT NULL );

Our main (and only one) html file:

<!DOCTYPE html>
<html ng-app="MessageService">
<head>
    <title>Angular Resource Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular-resource.min.js"></script>
    <script src="js/services.js"></script>
    <script src="js/controllers.js"></script>
</head>
<body ng-controller="MessageController">

<h2>Message list <a href="#" ng-click="refresh()">refresh</a></h2>
<ul>
    <li ng-repeat="message in messages">
        <a href="#" ng-click="deleteMessage($index, message.id)">delete</a>
        #{{message.id}} - {{message.author}} - {{message.message}}
        <a href="#" ng-click="selectMessage($index)">edit</a>
    </li>
</ul>

<form>
    <input type="text" ng-model="author" placeholder="author">
    <input type="text" ng-model="message" placeholder="message">

    <button ng-click="add()" ng-show='addMode'>Create</button>
    <button ng-click="update()" ng-hide='addMode'>Update</button>
    <button ng-click="cancel()" ng-hide='addMode'>Cancel</button>
</form>
</body>
</html>

As we can see we will use ng-app=”MessageService” defined within the js/services.js file:

angular.module('MessageService', ['ngResource']).factory('Message', ['$resource', function ($resource) {
    return $resource('/api/message/resource/:id');
}]);

And our controller in js/controllers.js:

function MessageController($scope, Message) {

    var currentResource;
    var resetForm = function () {
        $scope.addMode = true;
        $scope.author = undefined;
        $scope.message = undefined;
        $scope.selectedIndex = undefined;
    }

    $scope.messages = Message.query();
    $scope.addMode = true;

    $scope.add = function () {
        var key = {};
        var value = {author: $scope.author, message: $scope.message}

        Message.save(key, value, function (data) {
            $scope.messages.push(data);
            resetForm();
        });
    };

    $scope.update = function () {
        var key = {id: currentResource.id};
        var value = {author: $scope.author, message: $scope.message}
        Message.save(key, value, function (data) {
            currentResource.author = data.author;
            currentResource.message = data.message;
            resetForm();
        });
    }

    $scope.refresh = function () {
        $scope.messages = Message.query();
        resetForm();
    };

    $scope.deleteMessage = function (index, id) {
        Message.delete({id: id}, function () {
            $scope.messages.splice(index, 1);
            resetForm();
        });
    };

    $scope.selectMessage = function (index) {
        currentResource = $scope.messages[index];
        $scope.addMode = false;
        $scope.author = currentResource.author;
        $scope.message = currentResource.message;
    }

    $scope.cancel = function () {
        resetForm();
    }
}

Now the backend part. As we said before we will use Silex. We’re going to use also RouteCollections to define our routes (you can read about it here). So our Silex application will be:

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Routing\RouteCollection;
use Silex\Application;

$app = new Silex\Application();

$app['routes'] = $app->extend('routes', function (RouteCollection $routes, Application $app) {
        $loader     = new YamlFileLoader(new FileLocator(__DIR__ . '/config'));
        $collection = $loader->load('routes.yml');
        $routes->addCollection($collection);

        return $routes;
    }
);

$app->register(
    new Silex\Provider\DoctrineServiceProvider(),
    array(
        'db.options' => array(
            'driver' => 'pdo_sqlite',
            'path'   => __DIR__ . '/db/app.db.sqlite',
        ),
    )
);

$app->run();

We define our routes in the messageResource.yml

getAll:
  path: /resource
  defaults: { _controller: 'Message\MessageController::getAllAction' }
  methods:  [GET]

getOne:
  path: /resource/{id}
  defaults: { _controller: 'Message\MessageController::getOneAction' }
  methods:  [GET]

deleteOne:
  path: /resource/{id}
  defaults: { _controller: 'Message\MessageController::deleteOneAction' }
  methods:  [DELETE]

addOne:
  path: /resource
  defaults: { _controller: 'Message\MessageController::addOneAction' }
  methods:  [POST]

editOne:
  path: /resource/{id}
  defaults: { _controller: 'Message\MessageController::editOneAction' }
  methods:  [POST]

And finally our Resource controller:

<?php
namespace Message;

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

class MessageController
{
    public function getAllAction(Application $app)
    {
        return new JsonResponse($app['db']->fetchAll("SELECT * FROM messages"));
    }

    public function getOneAction($id, Application $app)
    {
        return new JsonResponse($app['db']
            ->fetchAssoc("SELECT * FROM messages WHERE id=:ID", ['ID' => $id]));
    }

    public function deleteOneAction($id, Application $app)
    {
        return $app['db']->delete('messages', ['ID' => $id]);
    }

    public function addOneAction(Application $app, Request $request)
    {
        $payload = json_decode($request->getContent());;

        $newResource = [
            'id'      => (integer)$app['db']
                ->fetchColumn("SELECT max(id) FROM messages") + 1,
            'author'  => $payload->author,
            'message' => $payload->message,
        ];
        $app['db']->insert('messages', $newResource);

        return new JsonResponse($newResource);
    }

    public function editOneAction($id, Application $app, Request $request)
    {
        $payload = json_decode($request->getContent());;
        $resource = [
            'author'  => $payload->author,
            'message' => $payload->message,
        ];
        $app['db']->update('messages', $resource, ['id' => $id]);

        return new JsonResponse($resource);
    }
}

And that’s all. Our prototype is working with AngularJS and Silex as REST provider. We must take care about one thing. Silex and AngularJS aren’t agree in one thing about REST services. AngularJS removes the trailing slash in some cases. Silex (and Symfony) returns HTTP 302 moved temporaly when we’re trying to access to the resource without the trailing slash but when we’re working with mounted controllers we will obtain a 404 page not found (bug/feature?). That’s because my REST service is /api/message/resource/:id instead of /api/message/:id. If I chose the second one, when angular tries to create a new resource, it will POST /api/message instead of POST /api/message/. We’re using mounted routes in this example:

messages:
  prefix: /message
  resource: messageResource.yml

With one simple Silex application (without mounted routes) in one file it doesn’t happen (we will see HTTP 302 and a new request with the trailing slash). Because of that I use this small hack to bypass the problem.

You can see the full code of the example in my github account

Follow

Get every new post delivered to your Inbox.

Join 869 other followers