Tagged: PHP

October Symfony Training Recap

Symfony WorkshopSolutionSet hosted its first symfony workshop last week on October 14-16th at our San Francisco office at 85 Second Street. Eight developers participated in the 3-day (9 to 5) training exercise targeted at beginner symfony users. People flew in from as far away as Michigan and Denmark! The following topics were covered:

  1. Introduction to Symfony
  2. From Flat File Application to MVC
  3. Actions and Templates
  4. Configuration and Model
  5. Model and Doctrine
  6. Conclusion and Environments
  7. Installation
  8. More with Doctrine
  9. Routing and Forms
  10. Admin Generator
  11. Session and Credentials
  12. Unit and Functional Testing

The material was well-matched to the experience level of the majority of attendees. In the future, we hope to develop an “advanced” curriculum that would benefit experienced symfony users. The next SolutionSet training will likely be held in San Francisco in early 2010. More details about future workshops will be posted at http://www.solutionset.com/symfony when they are finalized.

Doctrine with Nested I18N & Versionable

Recently the open source Symfony PHP framework project made it clear that the future of Symfony is Doctrine ORM. Doctrine is an incredibly powerful and useful tool due to its built in behaviors, these behaviors allow users to quickly enable complex relations and functionality with a few configuration settings.

One of the more advanced features of Doctrine is the ability to nest behaviors, or in essence stack them on top of each other for combined functionality. However one of the most useful potential combinations of behaviors in the default Doctrine 1.0 bundled with Symfony 1.2 is currently broken in Doctrine, nesting I18N with Versionable. This is noted in the Doctrine documentation under the nesting behaviors section. This nest would give you the ability to have a model that auto versioned while supporting content in multiple languages, a very handy tool for any CMS type application.

After fighting against the SQL insert issues to try to get the below example schema to work

Page:
  actAs:
    Timestampable: ~
    I18n:
      fields: [ title, nav_text, meta_keywords, meta_description, content ]
    Versionable: ~
  tableName: page
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    version:
      type: integer(4)
      notnull: true
      default: 0
    active:
      type: boolean
      notnull: true
      default: 1
    title:
      type: string(255)
      notnull: true
    nav_text: string(255)
    meta_keywords: string(2147483647)
    meta_description: string(2147483647)
    content: string(2147483647)

I realized that it is fairly straightforward to apply a quick fix to the problem. First we remove the Versionable from our original schema above as it doesn’t work the way we want it to. By default the Versionable behavior tries to create a duplicate table of the model appended with “_version”.  This is easy to recreate in our schema.

PageVersion:
  actAs:
    I18n:
      fields: [ title, nav_text, meta_keywords, meta_description, content ]
  tableName: page_version
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    orig_id:
      type: integer(4)
      notnull: true
    version:
      type: integer(4)
      notnull: true
    active:
      type: boolean
      notnull: true
    title:
      type: string(255)
      notnull: true
    nav_text: string(255)
    meta_keywords: string(2147483647)
    meta_description: string(2147483647)
    content: string(2147483647)
    created_at: timestamp
    updated_at: timestamp

We now have two near identical tables, the exception being the addition of 3 new columns in the page_version table. We will use these new columns to capture the timestampable behavior from the page table and capture the original page id.

Now that we have the two tables we need to alter our models to reproduce the Versionable behavior. Time to fire off a doctrine:build-model and lets’ start by setting up some queries in our PageVersion Table class.

class PageVersionTable extends Doctrine_Table
{
  public function retrieveVersion($object_id, $version)
  {
    $version = (int) $version;
    $object_id = (int) $object_id;
    if($version < 1 || $object_id < 1)
    {
      return null;
    }
    $q = $this->createQuery('v')
    ->where('v.orig_id = ?', $object_id)
    ->andWhere('v.version = ?', $version)
    ->leftJoin('v.Translation t');
    return $q->fetchOne();
  }

  public function retrieveMaxRevision($object_id)
  {
    $object_id = (int) $object_id;
    if($object_id < 1 )
    {
      return 1;
    }
    $q = $this->createQuery('v')
    ->select('MAX(v.version) as max')
    ->where('v.orig_id = ?', $object_id);
    $return = $q->setHydrationMode(Doctrine::HYDRATE_NONE)->fetchOne();
    return array_shift($return);
  }

  public function getAllVersionsQuery($orig_id)
  {
    $orig_id = (int) $orig_id;
    if($orig_id < 1)
    {
      return null;
    }
    $q = $this->createQuery('v')
    ->where('v.version >= ?', 1)
    ->andWhere('v.orig_id = ?', $orig_id)
    ->orderBy('v.version DESC');
    return $q;
  }
}

This gives us 3 useful methods.

  • retrieveVersion to retrieve a specific version out of the page_version table
  • retrieveMaxRevision to get the latest version number
  • getAllVersionsQuery to get all versions based on the original object id

Next we want to recreate the ->revert() method that Versionable provides. First let’s create a mapping function in our PageVersion Class, this will make translation from a PageVersion object to a Page object much easier.

class PageVersion extends BasePageVersion
{
  public function toRevertArray()
  {
    $thisArray = $this->toArray();
    $thisArray['id'] = $thisArray['orig_id'];
    unset($thisArray['orig_id'], $thisArray['id']);
    foreach($thisArray['Translation'] as $k => $v)
    {
      $thisArray['Translation'][$k]['id'] = $this->orig_id;
    }
    return $thisArray;
  }
}

Lastly we need to update the Page class to override the save function to automatically create PageVersion objects on each change and to also give us the needed methods to revert to an older revision.

class Page extends BasePage
{
  public function getVersionClass()
  {
    return __CLASS__.'Version';
  }

  public function getVersionObject()
  {
    $class = $this->getVersionClass();
    $object = new $class;
    return $object;
  }

  public function save(Doctrine_Connection $conn = null)
  {
    if(is_null($conn))
    {
      $conn = $this->_table->getConnection();
    }
    $this->calculateVersion();
    parent::save($conn);
    $this->mapToVersion();
  }

  public function calculateVersion()
  {
    if(!$this->isNew())
    {
      $this->version = Doctrine::getTable($this->getVersionClass())->retrieveMaxRevision($this->id) + 1;
    }
  }

  public function mapToVersion()
  {
    $version = $this->getVersionObject();
    $version->fromArray($this->toVersionArray());
    $version->save();
  }

  public function toVersionArray()
  {
    $thisArray = $this->toArray();
    $thisArray['orig_id'] = $thisArray['id'];
    unset($thisArray['id']);
    foreach($thisArray['Translation'] as $k => $v)
    {
      unset($thisArray['Translation'][$k]['id']);
    }
    return $thisArray;
  }

  public function revert($version)
  {
    $version = (int) $version;
    $objectVersion = Doctrine::getTable($this->getVersionClass())
    ->retrieveVersion($this->id, $version);
    $this->fromArray($objectVersion->toRevertArray());
  }
}

Now on each change the Page object is updated but also creates a PageVersion object. The PageVersion objects record the full history of our model including I18N fields. Reverting back to a revision is a simple as calling $page->revert($version);

All of the above methods are abstracted from using model specific namespaces so they are reusable and can be dropped in to any class. Now you have a working application that reproduces nesting Versionable and I18N.

Dreambot: A System Admin Robot

Dreambot

Two days ago I got word that I won the Grand Prize in the DreamHost API contest for my entry called Dreambot. Entries can be found here:

http://blog.dreamhost.com/2009/06/22/big-boy-time-is-up/

Dreambot is a secure Instant Messenger (IM) robot that runs on your Dreamhost server and performs possibly any server related tasks for you on demand. Dreambot’s core uses the XMPP protocol currently with Jabber Google Talk. Dreambot is fully customizable in that you can configure your Dreambot to respond to your specific set of commands sent to it. Dreambot is open source, object oriented, built in PHP5 and licensed under MIT.

More information on Dreambot can be found here:
http://dreambot.openovate.com/

The Twofer: Facebook and Wordpress

The other day I stumbled upon a very well put together Facebook Connect - Wordpress plugin. Given the task of finding a way to connect the two, a Google search pointed me to www.sociable.es.

Once installed, the plugin implements a widget into your Wordpress sidebar that allows users to log into their Facebook accounts and share a blog post with friends, post a blog article to their Facebook wall, share blog comments to facebook, even import registration data to the Wordpress application. The registration part is clever. As a new visitor to the Wordpress blog, a user simply click the “Connect with Facebook” badge and enters their Facebook credentials. In a snap a new Wordpress account is created based upon their Facebook profile and their profile image and other basic information is imported over.

Facebook and Wordpress

Check out a demo at http://www.onewelcomesone.com/wordpress/  - The demo is a clean installation of Wordpress with nothing but the plugin added. The overall setup took less than an hour and could be done by anyone.

Developed by Javier Reyes, the Wordpress plugin is easily installed through the Wordpress plugin directory and immediately configurable through the Wordpress administration interface. Backed with a straightforward read-me, the plugin is installed in 8 steps. For a noob, the toughest part of the installation is probably creating a Facebook application through www.facebook.com/developers but after that, it’s all drag and drop. Anyone who toys with the two applications will love this plugin.

Check it out, install it, enjoy it. If you have any questions, leave a comment. It’s an excellent way to start boosting traffic on your blog and getting your articles spread across larger social communities.

RnR? Or URLs For Modules

My first formal programming gig was pretty sweet. I worked with a bunch of scientists from the Field Station Programs at San Diego State University. I was tasked with availing their research results from the field to the web. They had been collecting data for a long time but it was silo’ed off and not easily accessible to other researchers and students. We got to do cool things like put remote sensors out in the wild and have the findings transmitted back to our servers. One of the field engineers (Pablo Bryant) called it “stunt science.” I’ve since co-opted the term and modified it lightly for my line of work: “stunt coding.” Back in those days, I was given a lot of latitude (no crazy deadlines and lots of funding from the government) to do some stunt coding. It was a lot of fun.

Things are a little slow around the office after the holidays and I got to do some stunt coding again. I’ve been thinking about this concept for a while. I’ve had many projects where a client wants some piece of functionality on their website, but to implement it directly within their architecture would have taken a lot of work. I’ve always thought it would be cool if such modules could be powered elsewhere remotely but easily presentable on client websites following a client-server arrangement. Think of it as URLs for modules.

I like pretty pictures, so I submit to you this:

The concept is pretty simple. You have a remote server that just cranks out modules in a variety of outputs. The URL format would be RESTful and look something like this:

http://www.someserver.com/module/modulename/arguments-for-the-module

Here’s a concrete example:

http://ahmad.web3.solutionset.com/module/facebook-status.php

This URL simply outputs my latest Facebook status. I can then modify it so that it can also dump out simple un-styled HTML:

http://ahmad.web3.solutionset.com/module/facebook-status.php?format=html

Or if you want some canned (and poorly designed) style:

http://ahmad.web3.solutionset.com/module/facebook-status.php?format=html-styled

And for those of you who are gluttons for punishment, XML output to be stylized via XSL:

http://ahmad.web3.solutionset.com/module/facebook-status.php?format=xml

So that’s the module server. Now for having it rendered on different client websites, I have two examples:

http://www.liquidphire.com/

http://testblog.liquidphire.com/

The first is my personal website and the latter is a vanilla WordPress installation. Both of these sites are simply calling the module server’s URL and displaying the output. It took me only a few minutes to implement it on each site. I think that was the second time I’ve ever played with WordPress. All of the horsepower to log in and get my Facebook status is being run on the module server. Why is this cool? Ostensibly, you could create more robust modules like “comments” and “ratings” and have the module server do all the heavy lifting while displaying it on another site where it would be non-trivial to implement the same functionality natively. You now have:

  • A built-in API for your modules
  • A great marketing vehicle for your website by distributing your modules across other platforms and partners
  • An easy way to extend your modules to other platforms, e.g. create a Facebook application (how meta!)

I’ve only taken it so far with the above examples. Throw in some AJAX and you could have some really cool interactive modules. You could even protect your widgets by having the module server identify which website is making the request (via token or sniffing the referrer) if you wanted authorized access to your modules.

This concept isn’t really new but I haven’t seen it practiced widely. Maybe if I come up with a cool marketing/branding name for it, it’ll catch on. I’m thinking “RnR” for “Remote ‘N RESTful” modules. Maybe you can suggest a better name?