Monthly Archives: July 2013

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

Advertisements

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