Blog Archives
How to configure Symfony’s Service Container to use Twitter API
Keeping on with the series about Symfony’s Services container (another posts here and here), now we will use the service container to use Twitter API from a service.
To use Twitter API we need to handle http requests. I’ve written several post about http request with PHP (example1, example2), but today we will use one amazing library to build clients: Guzzle. Guzzle is amazing. We can easily build a Twitter client with it. There’s one example is its landing page:
<?php
$client = new Client('https://api.twitter.com/{version}', array('version' => '1.1'));
$oauth = new OauthPlugin(array(
'consumer_key' => '***',
'consumer_secret' => '***',
'token' => '***',
'token_secret' => '***'
));
$client->addSubscriber($oauth);
echo $client->get('/statuses/user_timeline.json')->send()->getBody();
If we are working within a Symfony2 application or a PHP application that uses the Symfony’s Dependency injection container component you can easily integrate this simple script in the service container. I will show you the way that I use to do it. Let’s start:
The idea is simple. First we include guzzle within our composer.json and execute composer update:
"require": {
"guzzle/guzzle":"dev-master"
}
Then we will create two files, one to store our Twitter credentials and another one to configure the service container:
# twitter.conf.yml
parameters:
twitter.baseurl: https://api.twitter.com/1.1
twitter.config:
consumer_key: ***
consumer_secret: ***
token: ***
token_secret: ***
# twitter.yml
parameters:
class.guzzle.response: Guzzle\Http\Message\Response
class.guzzle.client: Guzzle\Http\Client
class.guzzle.oauthplugin: Guzzle\Plugin\Oauth\OauthPlugin
services:
guzzle.twitter.client:
class: %class.guzzle.client%
arguments: [%twitter.baseurl%]
calls:
- [addSubscriber, [@guzzle.twitter.oauthplugin]]
guzzle.twitter.oauthplugin:
class: %class.guzzle.oauthplugin%
arguments: [%twitter.config%]
And finally we include those files in our services.yml:
# services.yml
imports:
- { resource: twitter.conf.yml }
- { resource: twitter.yml }
And that’s all. Now we can use the service without problems:
<?php
namespace Gonzalo123\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction($name)
{
$twitterClient = $this->container->get('guzzle.twitter.client');
$status = $twitterClient->get('statuses/user_timeline.json')
->send()->getBody();
return $this->render('AppBundle:Default:index.html.twig', array(
'status' => $status
));
}
}
Building a Silex application from one Behat/Gherkin feature file
Last days I’ve playing with Behat. Behat is a behavior driven development (BDD) framework based on Ruby’s Cucumber. Basically with Behat we defenie features within one feature file. I’m not going to crate a Behat tutorial (you can read more about Behat here). Behat use Gherkin to write the features files. When I was playing with Behat I had one idea. The idea is simple: Can we use Gherking to build a Silex application?. It was a good excuse to study Gherking, indeed
.
Here comes the feature file:
Feature: application API
Scenario: List users
Given url "/api/users/list.json"
And request method is "GET"
Then instance "\Api\Users"
And execute function "listUsers"
And format output into json
Scenario: Get user info
Given url "/api/user/{userName}.json"
And request method is "GET"
Then instance "\Api\User"
And execute function "info"
And format output into json
Scenario: Update user information
Given url "/api/user/{userName}.json"
And request method is "POST"
Then instance "\Api\User"
And execute function "update"
And format output into json
Our API use this simple library:
<?php
namespace Api;
use Symfony\Component\HttpFoundation\Request;
class User
{
private $request;
public function __construct(Request $request)
{
$this->request = $request;
}
public function info()
{
switch ($this->request->get('userName')) {
case 'gonzalo':
return array('name' => 'Gonzalo', 'surname' => 'Ayuso');
case 'peter':
return array('name' => 'Peter', 'surname' => 'Parker');
}
}
public function update()
{
return array('infoUpdated');
}
}
<?php
namespace Api;
use Symfony\Component\HttpFoundation\Request;
class Users
{
public function listUsers()
{
return array('gonzalo', 'peter');
}
}
The idea is simple. Parse the feature file with behat/gherkin component and create a silex application. And here comes the “magic”. This is a simple working prototype, just an experiment for a rainy sunday.
<?php
include __DIR__ . '/../vendor/autoload.php';
define(FEATURE_PATH, __DIR__ . '/api.feature');
use Behat\Gherkin\Lexer,
Behat\Gherkin\Parser,
Behat\Gherkin\Keywords\ArrayKeywords,
Behat\Gherkin\Node\FeatureNode,
Behat\Gherkin\Node\ScenarioNode,
Symfony\Component\HttpFoundation\Request,
Silex\Application;
$keywords = new ArrayKeywords([
'en' => [
'feature' => 'Feature',
'background' => 'Background',
'scenario' => 'Scenario',
'scenario_outline' => 'Scenario Outline',
'examples' => 'Examples',
'given' => 'Given',
'when' => 'When',
'then' => 'Then',
'and' => 'And',
'but' => 'But'
],
]);
function getMatch($subject, $pattern) {
preg_match($pattern, $subject, $matches);
return isset($matches[1]) ? $matches[1] : NULL;
}
$app = new Application();
function getScenarioConf($scenario) {
$silexConfItem = [];
/** @var $scenario ScenarioNode */
foreach ($scenario->getSteps() as $step) {
$route = getMatch($step->getText(), '/^url "([^"]*)"$/');
if (!is_null($route)) {
$silexConfItem['route'] = $route;
}
$requestMethod = getMatch($step->getText(), '/^request method is "([^"]*)"$/');
if (!is_null($requestMethod)) {
$silexConfItem['requestMethod'] = strtoupper($requestMethod);
}
$instance = getMatch($step->getText(), '/^instance "([^"]*)"$/');
if (!is_null($instance)) {
$silexConfItem['className'] = $instance;
}
$method = getMatch($step->getText(), '/^execute function "([^"]*)"$/');
if (!is_null($method)) {
$silexConfItem['method'] = $method;
}
if ($step->getText() == 'format output into json') {
$silexConfItem['jsonEncode'] = TRUE;
}
}
return $silexConfItem;
}
/** @var $features FeatureNode */
$features = (new Parser(new Lexer($keywords)))->parse(file_get_contents(FEATURE_PATH), FEATURE_PATH);
foreach ($features->getScenarios() as $scenario) {
$silexConfItem = getScenarioConf($scenario);
$app->match($silexConfItem['route'], function (Request $request) use ($app, $silexConfItem) {
function getConstructorParams($rClass, $request) {
$parameters =[];
foreach ($rClass->getMethod('__construct')->getParameters() as $parameter) {
if ('Symfony\Component\HttpFoundation\Request' == $parameter->getClass()->name) {
$parameters[$parameter->getName()] = $request;
}
}
return $parameters;
}
$rClass = new ReflectionClass($silexConfItem['className']);
$obj = ($rClass->hasMethod('__construct')) ?
$rClass->newInstanceArgs(getConstructorParams($rClass, $request)) :
new $silexConfItem['className'];
$output = $obj->{$silexConfItem['method']}();
return ($silexConfItem['jsonEncode'] === TRUE) ? $app->json($output, 200) : $output;
}
)->method($silexConfItem['requestMethod']);
}
$app->run();
You can see the source code in github. What do you think?
How to rewrite urls with PHP 5.4′s built-in web server
PHP 5.4 comes with a flaming built-in web server. This server is (obviously) not suitable to use in production environments, but it’s great if we want to check one project quickly:
- git clone from github
- composer install to install dependencies
- run the built-in web server and test the application.
php -S localhost:8888 -t www/
But is very usual to use mod_rewrite or similar to send all requests to the front controller. With apache is pretty straight forward to do it:
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
But, does it work with the built-in web server? The answer is yes, but with another syntax. We only need to create one router file and start our server with this router:
<?php
// www/routing.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
return false;
} else {
include __DIR__ . '/index.php';
}
And now we start the server with:
php -S localhost:8888 www/routing.php
Easy, isn’t it?
How to send the output of Symfony’s process Component to a node.js server in Real Time with Socket.io
Today another crazy idea. Do you know Symfony Process Component? The Process Component is a simple component that executes commands in sub-processes. I like to use it when I need to execute commands in the operating system. The documentation is pretty straightforward. Normally when I want to collect the output of the script (imagine we run those scripts within a crontab) I save the output in a log file and I can check it even in real time with tail -f command.
This approach works, but I want to do it in a browser (call me crazy
). I’ve written a couple of posts with something similar. What I want to do now? The idea is simple:
First I want to execute custom commands with process. Just follow the process documentation:
<?php
use Symfony\Component\Process\Process;
$process = new Process('ls -lsa');
$process->setTimeout(3600);
$process->run();
if (!$process->isSuccessful()) {
throw new \RuntimeException($process->getErrorOutput());
}
print $process->getOutput();
Process has one cool feature, we can give feedback in real-time by passing an anonymous function to the run() method:
<?php
use Symfony\Component\Process\Process;
$process = new Process('ls -lsa');
$process->run(function ($type, $buffer) {
if ('err' === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
});
The idea now is to use this callback to send a TCP socket to one server with node.js
var LOCAL_PORT = 5600;
var server = require('net').createServer(function (socket) {
socket.on('data', function (msg) {
console.log(msg);
});
}).listen(LOCAL_PORT);
server.on('listening', function () {
console.log("TCP server accepting connection on port: " + LOCAL_PORT);
});
Now we change our php script to
<?php
include __DIR__ . "/../vendor/autoload.php";
use Symfony\Component\Process\Process;
function runProcess($command)
{
$address = 'localhost';
$port = 5600;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, $address, $port);
$process = new Process($command);
$process->setTimeout(3600);
$process->run(
function ($type, $buffer) use ($socket) {
if ('err' === $type) {
socket_write($socket, "ERROR\n", strlen("ERROR\n"));
socket_write($socket, $buffer, strlen($buffer));
} else {
socket_write($socket, $buffer, strlen($buffer));
}
}
);
if (!$process->isSuccessful()) {
throw new \RuntimeException($process->getErrorOutput());
}
socket_close($socket);
}
runProcess('ls -latr /');
Now with the node.js started, if we run the php script, we will see the output of the process command in the node’s terminal. But we want to show it in a browser. What can we do? Of course, socket.io. We change the node.js command to:
var LOCAL_PORT = 5600;
var SOKET_IO_PORT = 8000;
var ioClients = [];
var io = require('socket.io').listen(SOKET_IO_PORT);
var server = require('net').createServer(function (socket) {
socket.on('data', function (msg) {
ioClients.forEach(function (ioClient) {
ioClient.emit('log', msg.toString().trim());
});
});
}).listen(LOCAL_PORT);
io.sockets.on('connection', function (socketIo) {
ioClients.push(socketIo);
});
server.on('listening', function () {
console.log("TCP server accepting connection on port: " + LOCAL_PORT);
});
and finally we create a simple web client:
<script src="http://localhost:8000/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:8000');
socket.on('log', function (data) {
console.log(data);
});
</script>
Now if we start one browser we will see the output of our command line process within the console tab of the browser.
If you want something like webConsole, I also have created the example, With a Web UI enabling to send custom commands. You can see it in github.
Obviously that’s only one experiment with a lot of security issues that we need to take into account if we want to use it in production. What do you think?
Scroll desktop’s Web pages remotely with our smartphone, using Node.js and WebSockets
Why this script? OK. It was a crazy idea. It started with one “Is it possible? Yes, let’s code it” in my mind. Let start. I want to scroll one web page in the TV’s web browser (or PC’s browser) using my smartphone lying on my couch. I’ve got a wireless mouse so I don’t really need it, but scroll the TV browser with the smartphone sounds cool, isn’t it?
The idea is the following one:
- One QR code in our web page (added dinamically with JavaScrip with Google’s Chart API ). Write urls with the smartphone is hard and QR has a good hype, so we will add a QR code at the bottom of the web page with the link to the node.js server.
- One socket.io server built with a node.js server for the real time communications. This node.js server will serve also a jQuery Mobile application with four buttons (with express and jade):
- The server will register the WebSocket and send the real time commands to the browser (with one easy-to-hack security token).
- The browser will handle the socket.io actions and controls the scroll of the web page.
The code is probably crowded by bugs and security problems, but it works and it was enough in my experiment
:
The node.js server:
var io = require('socket.io').listen(8080);
var app = require('express').createServer();
app.set('view engine', 'jade');
app.set('view options', {
layout:false
});
app.get('/panel/:key', function (req, res) {
var key = req.params.key;
console.log(key);
res.render('mobile.jade', {key:key});
});
app.get('/action/:key/:y/:action', function (req, res) {
var key = req.params.key;
var y = req.params.y;
var action = req.params.action;
sockets[key].emit('scrollTo', {y:y, action:action});
res.send('OK');
});
app.listen(8000);
var sockets = {};
io.sockets.on('connection', function (socket) {
socket.on('setKey', function (key) {
sockets[key] = socket;
});
});
The jade template with the jquery mobile application:
!!! 5
html
head
meta(charset="utf-8")
meta(name="viewport", content="width=device-width, initial-scale=1")
title title
link(rel='stylesheet', href='http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css')
script(src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js')
script(src='http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js')
script(type='text/javascript')
$(document).bind('pageinit', function() {
$('#toTop').tap(function() {
$.get('/action/#{key}/0/go', function() {});
});
$('#toBotton').tap(function() {
$.get('/action/#{key}/max/go', function() {});
});
$('#toUp').tap(function() {
$.get('/action/#{key}/100/rew', function() {});
});
$('#toDown').tap(function() {
$.get('/action/#{key}/100/ffd', function() {});
});
});
body
#page1(data-role="page")
#header(data-theme="a", data-role="header")
h3 Header
#content(data-role="content")
a(data-role="button", data-transition="fade", data-theme="a", href="#", id="toTop", data-icon="minus", data-iconpos="left") Top
a(data-role="button", data-transition="fade", href="#", id="toUp", data-icon="arrow-u", data-iconpos="left") Up
a(data-role="button", data-transition="fade", href="#", id="toDown", data-icon="arrow-d", data-iconpos="left") Down
a(data-r
Our Html client page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>jQuery Smooth Scroll - Design Woop</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<p>
Lorem ipsum ….. put a big lorem ipsum here to make possible the scroll
</p>
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
<script src="client.js"></script>
</body>
</html>
And finally our client magic with the QR code and the functions to handle the node.js actions
var key = "secret";
function getDocHeight() {
var D = document;
return Math.max(
Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
Math.max(D.body.clientHeight, D.documentElement.clientHeight)
);
}
var socket = io.connect('http://localhost:8080');
var y = 0;
socket.emit('setKey', key);
socket.on('scrollTo', function (data) {
if (data.y == 'max') {
y = getDocHeight();
} else {
if (data.action == 'ffd') {
y += parseInt(data.y);
} else if (data.action == 'go') {
y = parseInt(data.y);
} else {
y -= parseInt(data.y);
}
}
window.scrollTo(0, y);
});
document.write('<img src="https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=http://192.168.2.3:8000/panel/' + key + '&choe=UTF-8" alt=""/>');
You can see the code in github too. We also can see the script in action here:
We can also add more features to our application but that’s enought for this experiment. What do you think?


























