Yahoo r3 is a powerful tool for building websites which could require multiple languages or dimensions. The r3 outputs may be plain text files, web templates, configuration files or even source code. Sometimes maintaining a big site translated into different languages can become a nightmare, but r3 lets you do it on an easy way. It offers a neat and powerful command line interface which will make your life easier. It can also be managed by using a web interface.
I know this could be a somewhat confusing thing to explain, so I’m going to try to give an example of what you can do with it. At Weblogs SL, we have a platform which handles instances of 37 blogs in 2 languages (Spanish and Portuguese), so we have to maintain 37×2 = 74 sites. They almost share the same layout structure, but sometimes we need to make specific changes on certain site (maybe a customized header or sidebar). r3 lets you do all this kind of things by specializing templates for a particular site/language. Coming back to our example, we have two dimensions: blog and language. Once we have created the dimensions, we can generate all the templates. These raw templates are parseable by the template engine included within our platform, so they are processed by the application afterwards. We can also put all the “static variables” for each blog (such as blog titles, URLs, paths, …) during this pre-build process.
So after far too much research, we came up with Yahoo r3, but we still had an itch to scratch: how can we integrate this into our continuous integration workflow? We are using Phing (and Java Ant) for building our sites, so it was nice to have some Phing tasks to work with r3. So I wrote these two tasks:
r3GenerateTask.php
/**
* r3 Generate Task
*
* PHP version 5
*
* @category Phing Task
* @package phing
* @author Alfonso Jimenez
* license http://www.gnu.org/licenses/gpl.html GPL
*
*/
class r3GenerateTask extends Task
{
/**
* path to r3 workspace
*
* var string
*/
protected $r3Workspace;
/**
* init method
*
* @return boolean
*/
public function init()
{
return true;
}
/**
* main method
*
* @return void
*/
public function main()
{
$command = 'r3 -c '. $this->Workspace .' generate -av';
$output = array();
$return = null;
try {
exec($command, $output, $return);
foreach ($output as $line) {
$this->log($line, Project::MSG_VERBOSE);
}
if ($return !== 0) {
throw new BuildException('Task exited with code'. $return);
}
} catch (BuildException $e) {
$op = Project::MSG_WARN;
if ($this->quiet === true) {
$op = Project::MSG_VERBOSE;
}
$this->log($e->getMessage(), $op);
}
}
}
r3SetVarTask.php
/**
* r3 setVar Task
*
* PHP version 5
*
* category Phing Task
* package phing
* author Alfonso Jimenez <yo@alfonsojimenez.com>
* license http://www.gnu.org/licenses/gpl.html GPL
*
*/
class r3SetVarTask extends Task {
/**
* path to r3 workspace
*
* var string
*/
protected $r3Workspace;
/**
* dimension
*
* @var string
*/
protected $dimension;
/**
* variable key
*
* @var string
*/
protected $key;
/**
* variable value
*
* @var string
*/
protected $value;
/**
* sets the r3 workspace path
*
* param string $r3Workspace
*
* return void
*/
public function setr3Workspace($r3Workspace)
{
$this->r3Workspace = $r3Workspace;
}
/**
* sets dimension
*
* param string $dimension
*
* return void
*/
public function setDimension($dimension)
{
$this->dimension = $dimension;
}
/**
* sets the variable key
*
* param string $key
*
* return void
*/
public function setKey($key)
{
$this->key = $key;
}
/**
* sets the variable value
*
* param string $value
*
* return void
*/
public function setValue($value)
{
$this->value = $value;
}
/**
* init method
*
* @return boolean
*/
public function init()
{
return true;
}
/**
* main method
*
* @return void
*/
public function main()
{
$command = ‘r3 -c ‘. $this‐>r3Workspace .’ var set ‘. $this‐>dimension
.’ ‘. $this‐>key .’ ‘. $this‐>value;
$output = array();
$return = null;
try {
exec($command, $output, $return);
foreach ($output as $line) {
$this->log($line, Project::MSG_VERBOSE);
}
if ($return !== 0) {
throw new BuildException(‘Task exited with code’. $return);
}
} catch (BuildException $e) {
$op = Project::MSG_WARN;
if ($this->quiet === true) {
$op = Project::MSG_VERBOSE;
}
$this->log($e->getMessage(), $op);
}
}
}
If you want to use these tasks in your Phing file, you have to place them in /usr/share/php/phing/extended/tasks/ first. Then you can call them by writing the following tag-commands:
<taskdef name=”r3-generate” classname=”extended.tasks.r3GenerateTask” />
<taskdef name=”r3-setVar” classname=”extended.tasks.r3SetVarTask” />
<r3-generate r3Workspace=”${workspace.dir}”></r3>
<r3-setVar r3Workspace=”${workspace.dir}” dimension=”${dimension}” key=”var_key” value=”${var_value}”></r3>
Let’s see an example of a real Phing file. Imagine that we have to write a task which needs to do the following steps:
- Get a Yahoo r3 workspace from a SVN repository (http://svn.test.com/trunk/r3)
- Build the Yahoo r3 workspace
- Move the generated templates into a certain directory
- Clean up the temporary files
So we can straightforward write a Phing task in order to follow this sequence of steps:
<project name="Yahoo r3 Templates Build" basedir="." default="build">
<property name="tmp.dir" value="/tmp/template" />
<property name="templates.dir" value="/home/r3/templates" />
<property name="svn" value="http://svn.test.com/trunk/r3" />
<target name="build" depends="init, generate, clean" />
<target name="init">
<taskdef name="r3-generate" classname="extended.tasks.r3GenerateTask" />
<mkdir dir="${tmp.dir}" />
<svncheckout svnpath="/usr/bin/svn" repositoryurl="${svn}" todir="${tmp.dir}"/>
</target>
<target name="generate">
<r3-generate r3Workspace="${tmp.dir}"></r3-generate>
</target>
<target name="clean">
<copy todir="${templates.dir}">
<fileset dir="${tmp.dir}/htdocs">
<include name="**" />
</fileset>
</copy>
<delete dir="${tmp.dir}" includeemptydirs="true" failonerror="true" />
</target>
</project>
Redis (REmote DIctionary Server) is a persistent key-value database with built-in net interface written in ANSI-C for Posix systems. Whilst it may at first seem like the wheel is being reinvented here, the need for something beyond a simple key-value database is pretty clear. It’s possible to use Redis like a replacement of memcached, with the main difference being the dataset is stored persistently – not volatile data – and Redis introduces new data structures such as list and sets. Furthermore, it implements atomic operations in order to interoperate with these data structures.
PHP.JS is a project with the purpose of porting standard PHP functions over to Javascript. The project was taken up by Kevin van Zonneveld, a dutch developer who had developed a small JS library of PHP functions for his job. Kevin shared the library on his blog and came into Open Source. Then many developers made contributions with new PHP functions written in JS and this is how the spark caught flame.



As you probably know, it’s possible to have multiple constructors in Java. They need to have the same name as the class, and they can only be distinguished by the number and type of arguments. In PHP5, you can only have one constructor. You can define it using the reserved word __construct. If the __construct function doesn’t exist, PHP5 will search for the old-style constructor function (by the name of the class). So if we cannot have multiple constructors, how could we create objects with different initial conditions? It’s not a big deal. There’s a pattern called Factory Method, which defines virtual constructors using static methods. Let’s see an example:
Writing intelligible code helps to increase the productivity of a developing team, even if you are an independent worker. Why is it so important to write intelligible code? How can it improve the productivity of my team? A messed up code could delay your partners understanding, or it could create a barrier for new developers. Even trying to understand your own code could be a real challenge as well. Here are 7 tips of how to make more intelligible PHP code (coding style tips):







