Blog Archives

Handling AngularJs POST requests with a Silex Backend

This days I working a lot with AngularJs applications (who doesn’t?). Normally my backend is a Silex application. It’s pretty straightforward to build a REST api with Silex. But when we play with an AngularJs client we need to face with a a problem. POST requests “doesn’t” work. That’s not 100% true. They work, indeed, but they speak different languages.

Silex assumes our POST requests are encoded as application/x-www-form-urlencoded, but angular encodes POST requests as application/json. That’s not a problem. It isn’t mandatory to use one encoder or another.

For example

name: Gonzalo
surname: Ayuso

If we use application/x-www-form-urlencoded, it’s encoded to:
name=Gonzalo&surname=Ayuso

And if we use application/json, it’s encoded to:
{ "name" : "Gonzalo", "surname" : "Ayuso" }

It’s the same but it isn’t.

Imagine this Silex example.

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

$app = new Application();

$app->post("/post", function (Application $app, Request $request) {
    return $app->json([
        'status' => true,
        'name'   => $request->get('name')
    ]);
});

This example works with application/x-www-form-urlencoded but it doesn’t work with application/json. We cannot use Symfony\Component\HttpFoundation\Request parameter’s bag as usual. We can get the raw request body with:

$request->getContent();

Our content in a application/json encoded Request is a JSON, so we can use json_decode to access to those parameters.

If we read the Silex documentation we can see how to handle those requests

http://silex.sensiolabs.org/doc/cookbook/json_request_body.html

In this post we’re going to enclose this code within a service provider. OK, that’s not really a service provider (it doesn’t provide any service). It just change the request (when we get application/json) without copy and paste the same code within each project.

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

$app = new Application();
$app->register(new AngularPostRequestServiceProvider());

$app->post("/post", function (Application $app, Request $request) {
    return $app->json([
        'status' => true,
        'name'   => $request->get('name')
    ]);
});

The service provider is very simple

namespace G;

use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Pimple\ServiceProviderInterface;
use Pimple\Container;

class AngularPostRequestServiceProvider implements ServiceProviderInterface
{
    public function register(Container $app)
    {
        $app->before(function (Request $request) {
            if ($this->isRequestTransformable($request)) {
                $transformedRequest = $this->transformContent($request->getContent());
                $request->request->replace($transformedRequest);
            }
        });
    }

    public function boot(Application $app)
    {
    }

    private function transformContent($content)
    {
        return json_decode($content, true);
    }

    private function isRequestTransformable(Request $request)
    {
        return 0 === strpos($request->headers->get('Content-Type'), 'application/json');
    }
}

You can see the whole code in my github account and also in packagist

Using OpenUI5 table and Angularjs

Last days I’ve been playing with OpenUI5. OpenUI5 is a web toolkit that SAP people has released as an open source project. I’ve read several good reviews about this framework, and because of that I started to hack a little bit with it. OpenUI5 came with a very complete set of controls. In this small example I want to use the “table” control. It’s just a datagrid. This days I playing a lot with Angular.js so I wanted to use together OpenUI5’s table control and Angularjs.

I’m not quite sure if it’s a good decision to use together both frameworks. In fact we don’t need Angular.js to create web applications using OpenUI5. OpenUI5 uses internally jQuery, but I wanted to hack a little bit and create one Angularjs directive to enclose one OpenUI5 datagrid.

First of all, we create one index.html. It’s just a boilerplate with angular + ui-router + ui-bootstrap. We also start our OpenUi5 environment with de default theme and including the table library

<!doctype html>
<html ng-app="G">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" href="assets/bootstrap/dist/css/bootstrap.min.css">

    <script src="assets/angular/angular.js"></script>
    <script src="assets/angular-ui-router/release/angular-ui-router.js"></script>
    <script src="assets/angular-bootstrap/ui-bootstrap-tpls.js"></script>

    <script id='sap-ui-bootstrap' type='text/javascript'
            src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
            data-sap-ui-theme='sap_bluecrystal'
            data-sap-ui-libs='sap.ui.commons, sap.ui.table'></script>

    <script src="js/ngOpenUI5.js"></script>

    <script src="js/app.js"></script>
    <link rel="stylesheet" href="css/app.css">
</head>
<body class="ng-cloak">

<div class="container">

    <div class="starter-template">
        <div ui-view></div>
    </div>
</div>

<script src="assets/html5shiv/dist/html5shiv.js"></script>
<script src="assets/respond/dest/respond.src.js"></script>

</body>
</html>

Then we create a directive enclosing the OpenUI5 needed code within a Angular module

(function () {
    'use strict';

    angular.module('ng.openui5', [])
        .directive('openui5Table', function () {

            function renderColumns(columns, oTable) {
                for (var i = 0; i <= columns.length; i++) {
                    oTable.addColumn(new sap.ui.table.Column(columns[i]));
                }
            }

            var link = function (scope, element) {

                var oData = scope.model.data,
                    oTable = new sap.ui.table.Table(scope.model.conf),
                    oModel = new sap.ui.model.json.JSONModel();

                oModel.setData({modelData: oData});
                renderColumns(scope.model.columns, oTable);

                oTable.setModel(oModel);
                oTable.bindRows("/modelData");
                oTable.sort(oTable.getColumns()[0]);

                oTable.placeAt(element);

                scope.$watch('model.data', function (data) {
                    if (data) {
                        oModel.setData({modelData: data});
                        oModel.refresh();
                    }
                }, true);

            };

            return {
                restrict: 'E',
                scope: {model: '=ngModel'},
                link: link
            };
        });
}());

And now we can create a simple Angular.js using the ng.openui5 module. In this application we configure the table and fetch the data from an externar API server

(function () {
    'use strict';

    angular.module('G', ['ui.bootstrap', 'ui.router', 'ng.openui5'])

        .value('config', {
            apiUrl: '/api'
        })

        .config(function ($stateProvider, $urlRouterProvider) {
            $urlRouterProvider.otherwise("/");
            $stateProvider
                .state('home', {
                    url: "/",
                    templateUrl: "partials/home.html",
                    controller: 'HomeController'
                });
        })

        .controller('HomeController', function ($scope, $http, $log, config) {
            $scope.refresh = function () {
                $http.get(config.apiUrl + '/gridData').success(function (data) {
                    $scope.datagrid.data = data;
                });
            };

            $scope.datagrid = {
                conf: {
                    title: "Table example",
                    navigationMode: sap.ui.table.NavigationMode.Paginator
                },
                columns: [
                    {
                        label: new sap.ui.commons.Label({text: "Last Name"}),
                        template: new sap.ui.commons.TextView().bindProperty("text", "lastName"),
                        sortProperty: "lastName",
                        filterProperty: "lastName",
                        width: "200px"
                    }, {
                        label: new sap.ui.commons.Label({text: "First Name"}),
                        template: new sap.ui.commons.TextField().bindProperty("value", "name"),
                        sortProperty: "name",
                        filterProperty: "name",
                        width: "100px"
                    }, {
                        label: new sap.ui.commons.Label({text: "Checked"}),
                        template: new sap.ui.commons.CheckBox().bindProperty("checked", "checked"),
                        sortProperty: "checked",
                        filterProperty: "checked",
                        width: "75px",
                        hAlign: "Center"
                    }, {
                        label: new sap.ui.commons.Label({text: "Web Site"}),
                        template: new sap.ui.commons.Link().bindProperty("text", "linkText").bindProperty("href", "href"),
                        sortProperty: "linkText",
                        filterProperty: "linkText"
                    }, {
                        label: new sap.ui.commons.Label({text: "Image"}),
                        template: new sap.ui.commons.Image().bindProperty("src", "src"),
                        width: "75px",
                        hAlign: "Center"
                    }, {
                        label: new sap.ui.commons.Label({text: "Gender"}),
                        template: new sap.ui.commons.ComboBox({
                            items: [
                                new sap.ui.core.ListItem({text: "female"}),
                                new sap.ui.core.ListItem({text: "male"})
                            ]
                        }).bindProperty("value", "gender"),
                        sortProperty: "gender",
                        filterProperty: "gender"
                    }, {
                        label: new sap.ui.commons.Label({text: "Rating"}),
                        template: new sap.ui.commons.RatingIndicator().bindProperty("value", "rating"),
                        sortProperty: "rating",
                        filterProperty: "rating"
                    }

                ]
            };
        })
    ;
}());

The API server is a simple Silex server

<?php
include __DIR__ . '/../../vendor/autoload.php';
use Silex\Application;

$app = new Application();
$app->get("/", function (Application $app) {

$app->get('gridData', function (Application $app) {
    return $app->json([
        ['lastName' => uniqid(), 'name' => "Al", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 4, 'src' => "images/person1.gif"],
        ['lastName' => "Friese", 'name' => "Andy", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 2, 'src' => "images/person1.gif"],
        ['lastName' => "Mann", 'name' => "Anita", 'checked' => false, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "female", 'rating' => 3, 'src' => "images/person1.gif"],
        ['lastName' => "Schutt", 'name' => "Doris", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "female", 'rating' => 4, 'src' => "images/person1.gif"],
        ['lastName' => "Open", 'name' => "Doris", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "female", 'rating' => 2, 'src' => "images/person1.gif"],
        ['lastName' => "Dewit", 'name' => "Kenya", 'checked' => false, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "female", 'rating' => 3, 'src' => "images/person1.gif"],
        ['lastName' => "Zar", 'name' => "Lou", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 1, 'src' => "images/person1.gif"],
        ['lastName' => "Burr", 'name' => "Tim", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 2, 'src' => "images/person1.gif"],
        ['lastName' => "Hughes", 'name' => "Tish", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 5, 'src' => "images/person1.gif"],
        ['lastName' => "Lester", 'name' => "Mo", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 3, 'src' => "images/person1.gif"],
        ['lastName' => "Case", 'name' => "Justin", 'checked' => false, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 3, 'src' => "images/person1.gif"],
        ['lastName' => "Time", 'name' => "Justin", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 4, 'src' => "images/person1.gif"],
        ['lastName' => "Barr", 'name' => "Gaye", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 2, 'src' => "images/person1.gif"],
        ['lastName' => "Poole", 'name' => "Gene", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 1, 'src' => "images/person1.gif"],
        ['lastName' => "Ander", 'name' => "Corey", 'checked' => false, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 5, 'src' => "images/person1.gif"],
        ['lastName' => "Early", 'name' => "Brighton", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 3, 'src' => "images/person1.gif"],
        ['lastName' => "Noring", 'name' => "Constance", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "female", 'rating' => 4, 'src' => "images/person1.gif"],
        ['lastName' => "Haas", 'name' => "Jack", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 2, 'src' => "images/person1.gif"],
        ['lastName' => "Tress", 'name' => "Matt", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "male", 'rating' => 4, 'src' => "images/person1.gif"],
        ['lastName' => "Turner", 'name' => "Paige", 'checked' => true, 'linkText' => "www.sap.com", 'href' => "http://www.sap.com", 'gender' => "female", 'rating' => 3, 'src' => "images/person1.gif"]
    ]);
});
$app->run();

And basically that’s all. You can see the whole project within my github account.

working example

working example

Why did this year has passed so swiftly? My 2014 Retrospective.

Today an original post. Maybe I’m the only one doing this, I know. 2014 is close to finish and I want to review how it went the year. Let’s start.

The bad parts:

  • My book about SOLID principles (in Spanish) isn’t released yet. It’s almost finished. It only needs a few reviews, but because one thing or another it looks like it isn’t be released this year. Lesson learned: Those kind of side projects must have a release date. If they haven’t, another side projects can grab our attention and they can be frozen.
  • No new languages learned this year. There was a good chance with Swift. A new language, but it didn’t attract my attention. Erlang books are still in my desk and also my aim to improve my Java skills didn’t success. I found nothing where apply my Java learning.

The good parts:

  • Finally I can say JavaScript is a first class language within my personal software stack. Various projects with JS this year and I feel very comfortable writing JavaScript code. That’s also the year of Angular.js (for me and probably a lot of people).
  • This year has been the year of mobile development for me. I’ve been involved with several projects using Cordova/Phonegap framework. I the beginning to install Cordova environment, compile, deploy the application into the device was something “heroic” but now it turns into trivial operations. I still remember my beginning with jQuery Mobile. Horrible. Then I started using Angular.js and Topcoat. Much better, but still problems when switching between Android and IOs. Finally I re-discover Ionic framework. Incredible project. Hybrid applications with angular.js with very complete toolkit. This year has been crowed by push notifications, camera plugins, barcode scanners, token based authorisations, Websockets and things like that. Now hybrid applications with Phonegap/Cordova live in my comfort zone along with Silex, Angular, PHP… (that’s means I need to find other places outside it)
  • The last part of the year I’ve been working a lot with automation tools: Bower and Grunt mainly. I also started to work with JavaScript testing with Karma and Jasmine
  • This year I’ve been a proud speaker at DeSymfony Day in Barcelona. On incredible weekend. Meeting with colleagues, speaker dinner, great conversations, and tourism in a great city. Definitely the most beautiful room for a conference that I ever been
  • Katayunos The coding dojo where we play with TDD and Pair Programming is still alive. Maybe not as continuous as I’d like, but we still meet together 20-25 people one Saturday morning to improve our programming skill, from time to time
  • My personal blog is still alive too. It’s close to be 5 years old (OK, technically speaking 6, but first year it wasn’t a serious one). More than 20k views per month and sometimes close to 30k (Hey, thank you for reading!)

And that’s all. It was a good year. Hopefully it will be worse than 2015 :)

See you!

Yet Another example of WebSockets, socket.io and AngularJs working with a Silex backend

Remember my last post about WebSockets and AngularJs? Today we’re going to play with something similar. I want to create a key-value interface to play with websockets. Let me explain it a little bit.

First we’re going to see the backend. One Silex application with two routes: a get one and a post one:

<?php

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

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

$app = new Application([
    'debug'      => true,
    'ioServer'   => 'http://localhost:3000',
    'httpServer' => 'http://localhost:3001',
]);

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

$app->register(new G\Io\EmitterServiceProvider($app['httpServer']));
$app->register(new DoctrineServiceProvider(), [
    'db.options' => [
        'driver' => 'pdo_sqlite',
        'path'   => __DIR__ . '/../../db/app.db.sqlite',
    ],
]);
$app->register(new G\Io\Storage\Provider(new SqlLiteStorage($app['db'])));

$app->get('conf', function (Application $app, Request $request) {
    $chanel = $request->get('token');
    return $app->json([
        'ioServer' => $app['ioServer'],
        'chanel'   => $chanel
    ]);
});

$app->get('/{key}', function (Application $app, $key) {
    return $app->json($app['gdb.get']($key));
});

$app->post('/{key}', function (Application $app, Request $request, $key) {
    $content = json_decode($request->getContent(), true);

    $chanel = $content['token'];
    $app->json($app['gdb.post']($key, $content['value']));

    $app['io.emit']($chanel, [
        'key'   => $key,
        'value' => $content['value']
    ]);

    return $app->json(true);
});

$app->run();

As we can see we register one service provider:

$app->register(new G\Io\Storage\Provider(new SqlLiteStorage($app['db'])));

This provider needs an instance of StorageIface

namespace G\Io\Storage;

interface StorageIface
{
    public function get($key);

    public function post($key, $value);
}

Our implementation uses SqlLite, but it’s pretty straightforward to change to another Database Storage or even a NoSql Database.

use Doctrine\DBAL\Connection;
use G\Io\Storage\StorageIface;

class SqlLiteStorage implements StorageIface
{
    private $db;

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

    public function get($key)
    {
        $statement = $this->db->executeQuery('select value from storage where key = :KEY', ['KEY' => $key]);
        $data      = $statement->fetchAll();

        return isset($data[0]['value']) ? $data[0]['value'] : null;
    }

    public function post($key, $value)
    {
        $this->db->beginTransaction();

        $statement = $this->db->executeQuery('select value from storage where key = :KEY', ['KEY' =>; $key]);
        $data      = $statement->fetchAll();

        if (count($data) > 0) {
            $this->db->update('storage', ['value' => $value], ['key' => $key]);
        } else {
            $this->db->insert('storage', ['key' => $key, 'value' => $value]);
        }

        $this->db->commit();

        return $value;
    }
}

We also register another Service provider:

$app->register(new G\Io\EmitterServiceProvider($app['httpServer']));

This provider’s responsibility is to notify to the websocket’s server when anything changes within the storage:

namespace G\Io;

use Pimple\Container;
use Pimple\ServiceProviderInterface;

class EmitterServiceProvider implements ServiceProviderInterface
{
    private $server;

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

    public function register(Container $app)
    {
        $app['io.emit'] = $app->protect(function ($chanel, $params) use ($app) {
            $s = curl_init();
            curl_setopt($s, CURLOPT_URL, '{$this->server}/emit/?' . http_build_query($params) . '&_chanel=' . $chanel);
            curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
            $content = curl_exec($s);
            $status  = curl_getinfo($s, CURLINFO_HTTP_CODE);
            curl_close($s);

            if ($status != 200) throw new \Exception();

            return $content;
        });
    }
}

The Websocket server is a simple socket.io server as well as a Express server to handle the backend’s triggers.

var
    express = require('express'),
    expressApp = express(),
    server = require('http').Server(expressApp),
    io = require('socket.io')(server, {origins: 'localhost:*'})
    ;

expressApp.get('/emit', function (req, res) {
    io.sockets.emit(req.query._chanel, req.query);
    res.json('OK');
});

expressApp.listen(3001);

server.listen(3000);

Our client application is an AngularJs application:

<!doctype html>
<html ng-app="app">
<head>
    <script src="//localhost:3000/socket.io/socket.io.js"></script>
    <script src="assets/angularjs/angular.js"></script>
    <script src="js/app.js"></script>
    <script src="js/gdb.js"></script>
</head>
<body>
 
<div ng-controller="MainController">
    <input type="text" ng-model="key">
    <button ng-click="change()">change</button>
</div>
 
</body>
</html>
angular.module('app', ['Gdb'])

    .run(function (Gdb) {
        Gdb.init({
            server: 'http://localhost:8080/gdb',
            token: '4b96716bcb3d42fc01ff421ea2cfd757'
        });
    })

    .controller('MainController', function ($scope, Gdb) {
        $scope.change = function () {
            Gdb.set('key', $scope.key).then(function() {
                console.log(&quot;Value set&quot;);
            });
        };

        Gdb.get('key').then(function (data) {
            $scope.key = data;
        });

        Gdb.watch('key', function (value) {
            console.log(&quot;Value updated&quot;);
            $scope.key = value;
        });
    })
;

As we can see the AngularJs application uses one small library called Gdb to handle the communications with the backend and WebSockets:

angular.module('Gdb', [])
    .factory('Gdb', function ($http, $q, $rootScope) {

        var socket,
            gdbServer,
            token,
            watches = {};

        var Gdb = {
            init: function (conf) {
                gdbServer = conf.server;
                token = conf.token;

                $http.get(gdbServer + '/conf', {params: {token: token}}).success(function (data) {
                    socket = io.connect(data.ioServer);
                    socket.on(data.chanel, function (data) {
                        watches.hasOwnProperty(data.key) ? watches[data.key](data.value) : null;
                        $rootScope.$apply();
                    });
                });
            },

            set: function (key, value) {
                var deferred = $q.defer();

                $http.post(gdbServer + '/' + key, {value: value, token: token}).success(function (data) {
                    deferred.resolve(data);
                });

                return deferred.promise;
            },

            get: function (key) {
                var deferred = $q.defer();

                $http.get(gdbServer + '/' + key, {params: {token: token}}).success(function (data) {
                    deferred.resolve(JSON.parse(data));
                });

                return deferred.promise;
            },

            watch: function (key, closure) {
                watches[key] = closure;
            }
        };

        return Gdb;
    });

And that’s all. You can see the whole project at github.

Building a Pimple/Container from a YAML file

The last May I attended to the great deSymfony day conference in Barcelona. At speaker’s dinner I had a great conversation with Máximo Cuadros about Dependency Injection Containers. We discuss about the customisation of containers. I said that I prefer Symfony´s DIC instead of Pimple, mainly because its configuration with YAML (or even xml) files. But In fact we can customise Pimple/Containers with YAML files in a similar way than we do it with Symfony’s DIC. In this example we’re going to see one way to do it.

We can easily extend the Pimple/Container and add a function to load a YAML files, parse them and build the container. But doing this we’re violating various SOLID principles. First we’re violating the Open-Close principle, because to extend our Pimple/Container with the new functionality we are adding new code within an existing class. We’re also violating the Dependency Inversion Principle and our new Pimple/Container is going to be harder to maintain. And finally we’re obviously violating the Single Responsibility Principle, because our new Pimple/Container is not only a DIC, it’s also a YAML parser.

There’s another way to perform this operation without upsetting SOLID principles. We can use the Symfony’s Config component

The idea is simple. Imagine this simple application:

use Pimple\Container;

$container = new Container();
$container['name'] = 'Gonzalo';

$container['Curl'] = function () {
    return new Curl();
};
$container['Proxy'] = function ($c) {
    return new Proxy($c['Curl']);
};

$container['App'] = function ($c) {
    return new App($c['Proxy'], $c['name']);
};

$app = $container['App'];
echo $app->hello();

We define the dependencies with code. But we want to define dependencies using a yml file for example:

parameters:
  name: Gonzalo

services:
  App:
    class:     App
    arguments: [@Proxy, %name%]
  Proxy:
    class:     Proxy
    arguments: [@Curl]
  Curl:
    class:     Curl

As we can see we’re using a similar syntax than Symfony’s DIC YAML files.
Now, with our new library we can use the following code:

use Pimple\Container;
use G\Yaml2Pimple\ContainerBuilder;
use G\Yaml2Pimple\YamlFileLoader;
use Symfony\Component\Config\FileLocator;

$container = new Container();

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

$app = $container['App'];
echo $app->hello();

Now our Pimple/Container is just a Pimple/Container nothing more. It doesn’t know anything about yaml, parsers and thing like that. It’s doesn’t have any extra responsibility. The responsibility of the parser falls on YamlFileLoader
You can see the library in my github account. It’s but one usage example of Symfony’s Config component. It only allows Yaml files, but it can be extended with Xml files adding a XmlFileLoader.

Upgrading Cordova-Android apps outside Google Play Store with angularjs

Recent months I’ve working with enterprise mobile applications. This apps are’t distributed using any marketplace, so I need to handle the distributions process. With Android you can compile your apps, create your APK files and distribute them. You can send the files by email, use a download link, send the file with bluetooth, or whatever. With iOS is a bit different. You need to purchase one Enterprise license, compile the app and distribute your IPA files using Apple’s standards.

OK, but this post is not about how to distribute apps outside the markets. This post is about one big problem that appears when we need to upgrade our apps. How do the user knows that there’s a new version of the application and he needs to upgrade? When we work inside Google Play Store we don’t need to worry about it, but if we distribute our apps manually we need do something. We can send push notifications or email to the user to inform about the new version. Let me show you how I’m doing it.

My problem isn’t only to let know to the user about a new version. Sometimes I also need to ensure that the user runs the last version of the app. Imagine a critical bug (solved in the last release) but the user don’t upgrade.

First we need to create a static html page where the user can download the APK file. Imagine that this is the url where the user can download the last version of the app:


http://192.168.1.1:8888/app.apk

We can check the version of the app against the server each time the user opens the application, but this check means network communication and it’s slow. We need to reduce the communication between client and server to the smallest expression and only when it’s strictly necessary. Check the version each time can be good in a desktop application, but it reduces the user experience with mobile apps. My approach is slightly different. Normally we use token based authentication within mobile apps. That’s means we need to send our token with all request. If we send the token, we also can send the version.

In a angular app we can define the version and the path of our apk using a key-value store.

.value('config', {
        version: 4,
        androidAPK: "http://192.168.1.1:8888/app.apk"
    })

Now we need to add version parameter to each request (we can easily create a custom http service to append this parameter to each request automatically, indeed)

$http.get('http://192.168.1.1:8888/api/doSomething', {params: {_version: config.version}})
    .success(function (data) {
        alert("OK");
    })
    .error(function (err, status) {
        switch (status) {
            case 410:
                $state.go('upgrade');
                break;
        }
    });

We can create a simple backend to take care of the version and throws an HTTP exception (one 410 HTTP error for example) if versions doesn’t match. Here you can see a simple Silex example:

<?php

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

use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;

$app = new Application([
    'debug'   => true,
    'version' => 4,
]);

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

$app->get('/api/doSomething', function (Request $request, Application $app) {
    if ($request->get('_version') != $app['version']) {
        throw new HttpException(410, "Wrong version");
    } else {
        return $app->json('hello');
    }
});

$app->run();

As you can see we need to take care about CORS

With this simple example we can realize if user has a wrong version within each server request. If version don’t match we can, for example redirect to an specific route to inform that the user needs to upgrade the app and provide a link to perform the action.

With Android we cannot create a link to APK file. It doesn’t work. We need to download the APK (using FileTransfer plugin) and open the file using webintent plugin.

The code is very simple:

var fileTransfer = new FileTransfer();
fileTransfer.download(encodeURI(androidUrl), 
    "cdvfile://localhost/temporary/app.apk",
    function (entry) {
        window.plugins.webintent.startActivity({
            action: window.plugins.webintent.ACTION_VIEW,
            url: entry.toURL(),
            type: 'application/vnd.android.package-archive'
        }, function () {
        }, function () {
            alert('Failed to open URL via Android Intent.');
            console.log("Failed to open URL via Android Intent. URL: " + entry.fullPath);
        });
    }, function (error) {
        console.log("download error source " + error.source);
        console.log("download error target " + error.target);
        console.log("upload error code" + error.code);
    }, true);

And basically that’s all. When user self-upgrade the app it closes automatically and he needs to open it again, but now with the correct version.

Token based authentication with Silex and AngularJS

According to my last post today we’re going to create a AngularJS application that uses the Silex Backend that we create previously. The idea of this application is to use it within a Phonegap/Cordova application running in a mobile device.

The application will be show a login form if device haven’t a correct token.

Gonzalo_Login_Example_and_LoginServiceProvider_php_-_token_-____work_projects_token_

And whit a correct token:

Gonzalo_Login_Example

Nothing new under the sun, isn’t it?

Our front-end application will use AngularJS and Topcoat.

<!DOCTYPE html>
<html xmlns:ng="http://angularjs.org" lang="es" ng-app="G">
<head>
    <meta charset="utf-8"/>
    <meta name="format-detection" content="telephone=no"/>
    <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
    <meta name="viewport"
          content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi"/>
    <link rel="stylesheet" type="text/css" href="/bower_components/topcoat/css/topcoat-mobile-light.min.css">
    <title>Gonzalo Login Example</title>
</head>
<body ng-controller="MainController">

<div ng-view class="main-content"></div>

<script src="/bower_components/angular/angular.min.js"></script>
<script src="/bower_components/angular-route/angular-route.min.js"></script>

<script src="js/app.js"></script>
<script src="js/services.js"></script>

</body>
</html>

And our AngularJS application:

'use strict';
var appControllers, G;
var host = 'http://localhost:8080'; // server API url

appControllers = angular.module('appControllers', []);
G = angular.module('G', ['ngRoute', 'appControllers']);

G.run(function (httpG) {
    httpG.setHost(host);
});

G.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.
        when('/login', {templateUrl: 'partials/login.html', controller: 'LoginController'}).
        when('/home', {templateUrl: 'partials/home.html', controller: 'HomeController'});
}]);

appControllers.controller('HomeController', ['$scope', 'httpG', '$location', function ($scope, httpG, $location) {
    $scope.hello = function () {
        httpG.get('/api/info').success(function (data) {
            if (data.status) {
                alert("Hello " + data.info.name + " " + data.info.surname);
            }
        });
    };

    $scope.logOut = function () {
        alert("Good bye!");
        httpG.removeToken();
        $scope.isAuthenticated = false;
        $location.path('login');
    };
}]);

appControllers.controller('MainController', ['$scope', '$location', 'httpG', function ($scope, $location, httpG) {
    $scope.isAuthenticated = false;

    if (httpG.getToken()) {
        $scope.isAuthenticated = true;
        $location.path('home');
    } else {
        $location.path('login');
    }
}]);


appControllers.controller('LoginController', ['$scope', '$location', 'httpG', function ($scope, $location, httpG) {
    $scope.user = {};

    $scope.doLogIn = function () {
        httpG.get('/auth/validateCredentials', {user: $scope.user.username, pass: $scope.user.password}).success(function (data) {
            if (data.status) {
                httpG.setToken(data.info.token);
                $scope.isAuthenticated = true;
                $location.path('home');
            } else {
                alert("login error");
            }
        }).error(function (error) {
            alert("Login Error!");
        });
    };

    $scope.doLogOut = function () {
        httpG.removeToken();
    };
}]);

In this example I’m using angular-route to handle the application’s routes. Nowadays I’m swaping to angular-ui-router, but this example I’m still using “old-style” routes. We define two partials:

partial/home.html

<div class="topcoat-button-bar full" style="position: fixed; bottom: 0px;">
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button full" ng-click="logOut()">
            <span class="">Logout</span>
        </button>
    </label>
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button--cta full" ng-click="hello()">
            <span class="">Hello</span>
        </button>
    </label>
</div>

partial/login.html

<div class="topcoat-navigation-bar">
    <div class="topcoat-navigation-bar__item center full">
        <h1 class="topcoat-navigation-bar__title">Login</h1>
    </div>
</div>

<ul class="topcoat-list__container">
    <li class="topcoat-list__item center">
        <input ng-model="user.username" class="topcoat-text-input--large" type="text" name="user"
               placeholder="Username"/>
    </li>
    <li class="topcoat-list__item center">
        <input ng-model="user.password" class="topcoat-text-input--large" type="password" name="pass"
               placeholder="Password"/>
    </li>
</ul>

<div class="topcoat-button-bar full" style="position: fixed; bottom: 0px;">
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button--cta full" ng-click="doLogIn()">
            <span class="">Login</span>
        </button>
    </label>
</div>

As we can see in the application we’re using a service to handle Http connections with the token information.

'use strict';

G.factory('httpG', ['$http', '$window', function ($http, $window) {
    var serviceToken, serviceHost, tokenKey;
    tokenKey = 'token';
    if (localStorage.getItem(tokenKey)) {
        serviceToken = $window.localStorage.getItem(tokenKey);
    }

    $http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";

    return {
        setHost: function (host) {
            serviceHost = host;
        },

        setToken: function (token) {
            serviceToken = token;
            $window.localStorage.setItem(tokenKey, token);
        },

        getToken: function () {
            return serviceToken;
        },

        removeToken: function() {
            serviceToken = undefined;
            $window.localStorage.removeItem(tokenKey);
        },

        get: function (uri, params) {
            params = params || {};
            params['_token'] = serviceToken;
            return $http.get(serviceHost + uri, {params: params});
        },

        post: function (uri, params) {
            params = params || {};
            params['_token'] = serviceToken;

            return $http.post(serviceHost + uri, params);
        }
    };
}]);

And that’s all. You can see the full example in my github account.

Token based authentication with Silex Applications

Imagine this simple Silex application:

use Silex\Application;

$app = new Application();

$app->get('/api/info', function (Application $app) {
    return $app->json([
        'status' => true,
        'info'   => [
            'name'    => 'Gonzalo',
            'surname' => 'Ayuso'
        ]]);
});

$app->run();

What happens if we want to use a security layer? We can use sessions. Sessions are the “standard” way to perform authentication in web applications, but when our application is a PhoneGap/Cordova application that uses a Silex server as API server, sessions aren’t the best way. The best way now is a token based authentication. The idea is simple. First we need a valid token. Our API server will give us a valid token if we send valid credentials in a login form. Then we need to send the token with each request (the same way than we send the session cookie with each request).

With Silex we can check this token and validate.

use Silex\Application;

$app = new Application();

$app->get('/api/info', function (Application $app) {
    $token = $app->get('_token');
    
    // here we need to validate the token ...

    return $app->json([
        'status' => true,
        'info'   => [
            'name'    => 'Gonzalo',
            'surname' => 'Ayuso'
        ]]);
});

$app->run();

It isn’t an elegant solution. We need to validate the token within all routes and that’s bored. We also can use middlewares and validates the token with $app->before(). We’re going to build something like this, but with a few variations. First I want to keep the main application as clean as possible. Validation logic must be separated from application logic, so we will extend Silex\Application. Our main application will be like this:

use G\Silex\Application;

$app = new Application();

$app->get('/api/info', function (Application $app) {
    return $app->json([
        'status' => true,
        'info'   => [
            'name'    => 'Gonzalo',
            'surname' => 'Ayuso'
        ]]);
});

$app->run();

Instead of Silex\Application we’ll use G\Silex\Application.

namespace G\Silex;

use Silex\Application as SilexApplication;
use G\Silex\Provider\Login\LoginBuilder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class Application extends SilexApplication
{
    public function __construct(array $values = [])
    {
        parent::__construct($values);

        LoginBuilder::mountProviderIntoApplication('/auth', $this);

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

Our new G\Silex\Application is a Silex\Application enabling CORS. We also mount a Service provider.

The responsibility of our API server will be check the token of every request and to provide one way to get a new token. To get a new token we will create a route “/auth/validateCredentials”. If a valid credentials are given, new token will be send to client.

Our Service provider has two parts: a service provider and a controller provider.

To mount both providers we will use a LoginBuilder class:

namespace G\Silex\Provider\Login;

use Silex\Application;

class LoginBuilder
{
    public static function mountProviderIntoApplication($route, Application $app)
    {
        $app->register(new LoginServiceProvider());
        $app->mount($route, (new LoginControllerProvider())->setBaseRoute($route));
    }
}

Our Controller provider:

namespace G\Silex\Provider\Login;

use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpFoundation\Request;
use Silex\ControllerProviderInterface;
use Silex\Application;

class LoginControllerProvider implements ControllerProviderInterface
{
    const VALIDATE_CREDENTIALS = '/validateCredentials';
    const TOKEN_HEADER_KEY     = 'X-Token';
    const TOKEN_REQUEST_KEY    = '_token';

    private $baseRoute;

    public function setBaseRoute($baseRoute)
    {
        $this->baseRoute = $baseRoute;

        return $this;
    }

    public function connect(Application $app)
    {
        $this->setUpMiddlewares($app);

        return $this->extractControllers($app);
    }

    private function extractControllers(Application $app)
    {
        $controllers = $app['controllers_factory'];

        $controllers->get(self::VALIDATE_CREDENTIALS, function (Request $request) use ($app) {
            $user   = $request->get('user');
            $pass   = $request->get('pass');
            $status = $app[LoginServiceProvider::AUTH_VALIDATE_CREDENTIALS]($user, $pass);

            return $app->json([
                'status' => $status,
                'info'   => $status ? ['token' => $app[LoginServiceProvider::AUTH_NEW_TOKEN]($user)] : []
            ]);
        });

        return $controllers;
    }

    private function setUpMiddlewares(Application $app)
    {
        $app->before(function (Request $request) use ($app) {
            if (!$this->isAuthRequiredForPath($request->getPathInfo())) {
                if (!$this->isValidTokenForApplication($app, $this->getTokenFromRequest($request))) {
                    throw new AccessDeniedHttpException('Access Denied');
                }
            }
        });
    }

    private function getTokenFromRequest(Request $request)
    {
        return $request->headers->get(self::TOKEN_HEADER_KEY, $request->get(self::TOKEN_REQUEST_KEY));
    }

    private function isAuthRequiredForPath($path)
    {
        return in_array($path, [$this->baseRoute . self::VALIDATE_CREDENTIALS]);
    }

    private function isValidTokenForApplication(Application $app, $token)
    {
        return $app[LoginServiceProvider::AUTH_VALIDATE_TOKEN]($token);
    }
}

And our Service provider:

namespace G\Silex\Provider\Login;

use Silex\Application;
use Silex\ServiceProviderInterface;

class LoginServiceProvider implements ServiceProviderInterface
{
    const AUTH_VALIDATE_CREDENTIALS = 'auth.validate.credentials';
    const AUTH_VALIDATE_TOKEN       = 'auth.validate.token';
    const AUTH_NEW_TOKEN            = 'auth.new.token';

    public function register(Application $app)
    {
        $app[self::AUTH_VALIDATE_CREDENTIALS] = $app->protect(function ($user, $pass) {
            return $this->validateCredentials($user, $pass);
        });

        $app[self::AUTH_VALIDATE_TOKEN] = $app->protect(function ($token) {
            return $this->validateToken($token);
        });

        $app[self::AUTH_NEW_TOKEN] = $app->protect(function ($user) {
            return $this->getNewTokenForUser($user);
        });
    }

    public function boot(Application $app)
    {
    }

    private function validateCredentials($user, $pass)
    {
        return $user == $pass;
    }

    private function validateToken($token)
    {
        return $token == 'a';
    }

    private function getNewTokenForUser($user)
    {
        return 'a';
    }
}

Our Service provider will have the logic to validate credentials, token and it must be able to generate a new token:

    private function validateCredentials($user, $pass)
    {
        return $user == $pass;
    }

    private function validateToken($token)
    {
        return $token == 'a';
    }

    private function getNewTokenForUser($user)
    {
        return 'a';
    }

As we can see the logic of the example is very simple. It’s just an example and here we must to perform our logic. Probably we need to check credentials with our database, and our token must be stored somewhere to be validated later.

You can see the example in my github account. In another post we will see how to build a client application with angularJs to use this API server.

Yet another Database Abstraction layer with PHP and DBAL

I’m not a big fan of ORMs. I feel very confortable working with raw SQLs and because of that I normally use DBAL (or PDO in old projects). I’ve got one small library to handle my dayly operations with databases and today I’ve written this library

First of all imagine one DBAL connection. I’m using a sqlite in-memomy database in this example but we can use any database supported by DBAL (aka “almost all”):

use Doctrine\DBAL\DriverManager;

$conn = DriverManager::getConnection([
    'driver' => 'pdo_sqlite',
    'memory' => true
]);

We can also create one DBAL connection from a PDO connection. It’s usefull to use DBAL within legacy applications instead of creating a new connection (remember that DBAL works over PDO)

use Doctrine\DBAL\DriverManager;

$conn = DriverManager::getConnection(['pdo' => new PDO('sqlite::memory:')]);

Now we set up the database for the example

$conn->exec("CREATE TABLE users (
            userid VARCHAR PRIMARY KEY  NOT NULL ,
            password VARCHAR NOT NULL ,
            name VARCHAR,
            surname VARCHAR
            );");
$conn->exec("INSERT INTO users VALUES('user','pass','Name','Surname');");
$conn->exec("INSERT INTO users VALUES('user2','pass2','Name2','Surname2');");

Our table “users” has two records. Now we can start to use our library.

First we create a new instance of our library:

use G\Db;

$db = new Db($conn);

Now a simple query from a string:

$data = $db->select("select * from users");

Sometimes I’m lazy and I don’t want to write the whole SQL string and I want to perform a select * from table:

use G\Sql;
$data = $db->select(SQL::createFromTable("users"));

Probably we need to filter our Select statement with a WHERE clause:

$data = $db->select(SQL::createFromTable("users", ['userid' => 'user2']));

And now something very intersting (at least for me). I want to iterate over the recordset and maybe change it. Of course I can use “foreach” over $data and do whatever I need, but I preffer to use the following sintax:

$data = $db->select(SQL::createFromTable("users"), function (&$row) {
    $row['name'] = strtoupper($row['name']);
});

For me it’s more readable. I iterate over the recordset and change the row ‘name’ to uppercase. Here you can see what is doing my “select” function:

/**
* @param Sql|string $sql
* @param \Closure $callback
* @return array
*/
public function select($sql, \Closure $callback = null)
{
    if ($sql instanceof Sql) {
        $sqlString = $sql->getString();
        $parameters = $sql->getParameters();
        $types = $sql->getTypes();
    } else {
        $sqlString = $sql;
        $parameters = [];
        $types = [];
    }

    $statement = $this->conn->executeQuery($sqlString, $parameters, $types);
    $data = $statement->fetchAll();
    if (!is_null($callback) && count($data) > 0) {
        $out = [];
        foreach ($data as $row) {
            if (call_user_func_array($callback, [&$row]) !== false) {
                $out[] = $row;
            }
        }
        $data = $out;
   }

   return $data;
}

And finally transactions (I normally never use autocommit and I like to handle transactions by my own)

$db->transactional(function (Db $db) {
    $userId = 'temporal';

    $db->insert('users', [
        'USERID'   => $userId,
        'PASSWORD' => uniqid(),
        'NAME'     => 'name3',
        'SURNAME'  => 'name3'
    ]);

    $db->update('users', ['NAME' => 'updatedName'], ['USERID' => $userId]);
    $db->delete('users', ['USERID' => $userId]);
});

The “transactional” function it’s very simmilar than DBAL’s transactional function

public function transactional(\Closure $callback)
{
    $out = null;
    $this->conn->beginTransaction();
    try {
        $out = $callback($this);
        $this->conn->commit();
    } catch (\Exception $e) {
        $this->conn->rollback();
        throw $e;
    }

    return $out;
}

I change a little bit because I like to return a value within the closure and allow to do things like that:

$status = $db->transactional(function (Db $db) {
    $userId = 'temporal';

    $db->insert('users', [
        'USERID'   => $userId,
        'PASSWORD' => uniqid(),
        'NAME'     => 'name3',
        'SURNAME'  => 'name3'
    ]);

    $db->update('users', ['NAME' => 'updatedName'], ['USERID' => $userId]);
    $db->delete('users', ['USERID' => $userId]);

    return "OK"
});

The other functions (insert, update, delete) only bypass the calls to DBAL’s funcitons:

private $conn;

public function __construct(Doctrine\DBAL\Connection $conn)
{
    $this->conn = $conn;
}

public function insert($tableName, array $values = [], array $types = [])
{
    $this->conn->insert($tableName, $values, $types);
}

public function delete($tableName, array $where = [], array $types = [])
{
    $this->conn->delete($tableName, $where, $types);
}

public function update($tableName, array $data, array $where = [], array $types = [])
{
    $this->conn->update($tableName, $data, $where, $types);
}

And that’s all. You can use the library with composer and download at github.

BTW I’ve test the new Sensiolabs product (SensioLabs Insight) to analyze the code and verify good practices and I’ve got the Platinum medal #yeah!

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.

Follow

Get every new post delivered to your Inbox.

Join 1,027 other followers