Blog

Posts Tagged ‘open source’

Adding ORDER BY FIELD to Propel Criterias

Posted on:Tuesday, October 13th, 2009 by Ashish Datta

Every now and then, we use Sphinx to provide full text searching in MySQL InnoDB tables. Sphinx is pretty solid. It’s easy to set up, pretty fast, and easy to deploy.

My one big issue with Sphinx has always been making it play nice with Symfony, specifically Propel. The way Sphinx returns a result set is as an ordered list of [id, weight] for each document it matched. As outlined here the idea is to then hit your MySQL server to return the actual documents and use “ORDER BY FIELD(id, [id list])” to keep them in the right order that you received the list.

The problem is, Propel Criteria objects provide no mechanism to set an ORDER BY FIELD. This is an issue because if you drop Criterias you loose Propel Pagers which generally adds to a lot of duplicated code and is honestly just not very elegant.

Anyway, after some thought I came up with this solution.

If you read through the definition of “Criteria::addDescendingOrderByColumn()”:

	/**
	 * Add order by column name, explicitly specifying descending.
	 *
	 * @param      string $name The name of the column to order by.
	 * @return     Criteria Modified Criteria object (for fluent API)
	 */
	public function addDescendingOrderByColumn($name)
	{
		$this->orderByColumns[] = $name . ' ' . self::DESC;
		return $this;
	}

All it really does is add the second part of the ORDER BY clause to an array which then gets joined up to build the final SQL. Because of this, you can actually just add an element onto the orderByColumns array which will cause Propel to execute an ORDER BY FIELD SQL statement.

To make the magic happen, I sub-classed Criteria and then added a addOrderByField() function to let me add a field to order by as well as a list to order by.


class sfCriteria extends Criteria {

  private $myOrderByColumns = array();

  /**
   * Add an ORDER BY FIELD clause.
   *
   * @param String $name The field to order by.
   * @param Array $elements A list to order the elements by.
   * @return unknown
   */
  public function addOrderByField($name, $elements)
  {
    $this->myOrderByColumns[] = ' FIELD(' . $name . ', ' . join(", ", $elements) . ')';
    return $this;
  }

  public function getOrderByColumns(){
    return array_merge( $this->myOrderByColumns, parent::getOrderByColumns() );
  }
}

To use it, do something like this:

$ids = array(1, 3, 7);
$c = new sfCriteria();
$c->add( SomeModelPeer::ID, $ids, Criteria::IN);
$c->addOrderByField( SomeModelPeer::ID, $ids);
$results = SomeModelPeer::doSelect( $c );

And thats about it. Since sfCriteria is a sub-class of Criteria the code works seamlessly with existing PropelPagers and anything else that expects a Propel Criteria.

FOSS Saturday: sfFbConnectGuardPlugin – sfGuard meets FB Connect

Posted on:Saturday, September 12th, 2009 by Ashish Datta

I was slaving over a hot keyboard all Friday!

But at last it is done – FBConnect for sfGuard.

Get it here http://www.symfony-project.org/plugins/sfFbConnectGuardPlugin

A detailed explanation of how to install it and use it is on the Symfony site.

Anyway, the plugin basically just introduces a new table to keep track of Facebook IDs <---> sfGuardUserIds

Here’s a fun nugget. One of the problems with using FB Connect is that you can’t mug a user’s email address from Facebook. Obviously this is a smart move on Facebook’s part but it makes life hard for my Nigerian spammer friends. If you want to snag a user’s email address (or anything else for that matter) while still using Facebook Connect here’s a sketch of how to do it.

Everything is the same except you can’t use Facebook’s FBML to render the FB Connect button. What you want to do instead is trigger the “connect” event by hand. Here is basically how we do it:

  1. The user requests to sign up.
  2. We pop up a Lightbox using Thickbox
  3. We ask the user for their email address and verify that is valid and unique via AJAX in the background.
  4. The validation routing sets an attribute on the user using setAttribute() that contains the entered email address.
  5. We close the Lightbox and initiate a Facebook Connect request with FB.Connect.requireSession
  6. In our createFbUser() method we get the attribute back and save it with the new user

Bam. Got the user’s email address and logged them in via FB Connect.

FOSS Fridays: MacGyvered Key/Value in Symfony

Posted on:Friday, August 7th, 2009 by Ashish Datta

On a project we’re currently working on, we arrived at a situation where our client had a loose and very fluid idea of the information he wanted to store about certain objects in his application. We didn’t specifically know the number of fields or the format of the data. Continually modifying the schema would of been painful so I wanted to try something different.

Since the data is more or less non-relational (it only relates to the object that owns it), what I really wanted was an ad-hoc key/value store. But I didn’t want to break Propel’s ORM abstractions. I still wanted to be able to do:

$company->getMission();

With the new system.

Turns out you basically can. Here’s how it works:

  1. Add a “dynamic_field” table to your schema. (definition is below)
  2. Override the __call(), hydrate(), and save() functions in Propel model file that you want to MacGyver.
  3. Pray.

Definition of the dynamic_field table:






  

So the idea is we want to basically build a Propel Behaviour to capture any undefined get/set calls and “get” the data out of the dynamic_field table or “set” the data by storing the value into the table. Since the table stores the model class and model id, the “keys” only have to be unique by model (just like Propel normally works).

Here is the code you need to add to the model file:

public function __call($method, $arguments){

  // snag the dynamic setters
  if(strpos($method, "set") !== false
      && $method[3] === strtoupper($method[3])){
	  $name = strtolower( substr($method, 3) );
	  $this->dynamicFields[ $name ] = array_pop( $arguments );
	  return true;
  }

  // snag the dynamic getters
  if(strpos($method, "get") !== false
      && $method[3] === strtoupper($method[3])){
        $name = strtolower( substr($method, 3) );

      if( array_key_exists($name, $this->hydratedFields) ){
        	return $this->hydratedFields[$name];
      }

       if( array_key_exists($name, $this->dynamicFields) ){
        	return $this->dynamicFields[ $name ];
        }

      	return null;
    }

    return parent::__call($method, $arguments);
}

public function hydrate($row, $startcol = 0, $rehydrate = false)
{
  parent::hydrate($row, $startcol, $rehydrate);
  // pull in our dynamic fields while we're at it
  $c = new Criteria();
  $c->add( DynamicFieldPeer::MODEL, get_class($this) );
  $c->add( DynamicFieldPeer::MODEL_ID, $this->getId() );
  $dynamic = DynamicFieldPeer::doSelect( $c );

  foreach($dynamic as $d){
     $this->hydratedFields[ $d->getFieldName() ] = unserialize( $d->getFieldValue() );
  }

  return true;
}

  public function save(PropelPDO $con = null){

	  // save the dyanmic ones
    if( count($this->dynamicFields) ){

    	// grab the old ones and update stuff
      $keys = array_keys($this->dynamicFields);
      $c = new Criteria();
      $c->add( DynamicFieldPeer::MODEL, get_class($this) );
      $c->add( DynamicFieldPeer::MODEL_ID, $this->getId() );
      $c->add( DynamicFieldPeer::FIELD_NAME, $keys, Criteria::IN );
      $savedFields = DynamicFieldPeer::doSelect( $c );

      foreach($savedFields as $sf){
      	$sf->setFieldValue( serialize( $this->dynamicFields[$sf->getFieldName()] ) );
      	$sf->save();
      	unset( $this->dynamicFields[$sf->getFieldName()] );
      }

		  foreach( $this->dynamicFields as $key => $val ){
			  $df = new DynamicField();
			  $df->setModel( get_class($this) );
			  $df->setModelId( $this->getId() );
			  $df->setFieldName( $key );
			  $df->setFieldValue( serialize( $val ) );
			  $df->save();
		  }

	  }

	  return parent::save($con);
  }

The code captures any undefined get/set calls and then deals with them appropriately. It won’t serialize the fields until the save() call (just like regular Propel objects). I also overloaded the hydrate() function so that the object will fetch all of its dynamic fields in one shot, as opposed one query per get.

Using the modified objects is exactly like regular Propel objects, the changes are entirely transparent except that you can get/set anything you want.

For example:

$company = CompanyPeer::retrieveByPK( 5 );
$company->setVision( "this is my vision" );
echo $company->getVision();

Will work even though there is no “vision” column on the company table. Magic.

There is one big problem with this trick though. Because of the Propel class hierarchy, there isn’t any way to introduce this code in one file and have other objects inherit the changes. You have to manually copy it to any model file that you want to enable it for.

Google Calender embed missing events

Posted on:Tuesday, August 4th, 2009 by Ashish Datta

So we decided to use the Google Calendar API in one of our applications to allow users to easily view and export events from outside the app. In general, the API was working well – I was using the Zend library to interact with Google and things seemed fine.

That was until I tried to embed the calendar using Google’s iframe embed code. For some reason, events weren’t showing up in the embeded iframe calendar even though they were showing up in the actual calendar on calendar.google.com. Even stranger, the events were present in a JSON object on the embeded page and they were showing up in the RSS feed for the calendar.

After literally days of debugging and experimenting I finally found out the culprit.

For some reason, events created via the API that start and end at exactly the same time – say a start date of 08-05-2009 10:00:00 and an end date of 08-05-2009 10:00:00 don’t render on the embeded iframe calendar.

What is even more bizarre is that if you create an event via the web interface that starts and ends at the same time, it will render correctly on an embeded calendar.

Anyway, that was weird. All the events without explicit start and end times now last a grand total of one minute.

PS. Kudos to Daum for finding a constant for PHP’s date() function to generate RFC3339 timestamps.

Use like so:

  $date = date(DATE_RFC3339, $timestamp);

To get back a valid RFC3339 for the Google Calendar API.

FOSS Fridays: OpenSSL in PHP

Posted on:Friday, July 31st, 2009 by Ashish Datta

Well Twitter has “Follow Fridays” so I thought we should do FOSS Fridays. I don’t really have a plan for this and it might not last but let’s see where it goes.

In the last few days a couple of people have asked for tips on how to use OpenSSL from PHP. So here is a snippet on how to do it. This comes out of an application that provides a shared authentication system between our client’s LDAP system and their partner’s systems.

It works like so:

  1. Users login to the application using their LDAP credentials.
  2. When the users request to visit the partner site, our system packages up their login information, encrypts it, signs it, and shoots it along with the user to the partner site.
  3. Next, the partner checks if the user has an account and if they do it logs them in. Otherwise, it creates them a new account and logs them in.

All of this is done transparently so that the user doesn’t know they’ve actually left the original site.

Here is the code to do it. PS. it’s from a Symfony application.

$user = $this->getUser();

$profile = $user->getProfile();

if(is_null($profile)){ die("Could not get user profile?"); }

$email = $profile->getEmail();

$firstName = $profile->getFirstName();

$lastName = $profile->getLastName();

$password = $request->getParameter("password");

$keyText = file_get_contents(sfConfig::get("sf_root_dir") . "/" . sfConfig::get("app_their_public_key"));

$theirPublicKey = openssl_pkey_get_public($keyText);

$keyText = file_get_contents(sfConfig::get("sf_root_dir") . "/" . sfConfig::get("app_our_private_key"));

$outPrivateKey = openssl_pkey_get_private($keyText);

$arr = array();

$arr["U_EMAIL"] = $email;

$arr["U_PASSWORD"] = $password;

$arr["U_FIRST_NAME"] = $firstName;

$arr["U_LAST_NAME"] = $lastName;

$arr["RL_E"] = $this->generateUrl("ps_error", array(), true);

$arr["RL_S"] = "PRIVATE URL";

$arr["ETIME"] = time() + 60;

$queryString = http_build_query($arr);

$res = openssl_sign($queryString, $signature, $outPrivateKey);

if(!$res){ throw new sfException("Could not sign the payload!", 1); }

$t = openssl_pkey_get_details($theirPublicKey);

$t = (int) ($t['bits'] / 8 ) - 11;

$l=strlen($queryString);

$cryptPayload = '';

for ($i=0; $i<$l; $i+= $t) {

  $block = substr($queryString, $i, $t);

  if (!openssl_public_encrypt($block,$tS, $theirPublicKey)){
    throw new sfException('failed encrypt', 1);
   }

  $cryptPayload .= $tS;
}

$this->encodedSignature = base64_encode($signature);

$this->encodedData = base64_encode($cryptPayload);

The net result of all of this is an encrypted payload with the user’s credentials and a signature of the payload. The payload is encrypted with “their” public key and then signed with “our” private key. This ensures that only they can open the package and only we can generate valid signatures.

Happy Friday!

Extracting text from PDFs without pdftotext

Posted on:Tuesday, June 16th, 2009 by Ashish Datta

For a recent project, I had to extract the text out of a PDF so that I could save it into a database table.

Normally, I would of used the popular pdftotext program but it wasn’t available in the particular environment I was working in. I contact support and they advised that the XPDF package has several X windows dependencies and that’s why they had not installed it. Fair enough.

I poked around a bit and found Apache’s PDFBox library. I downloaded the package and looked at the examples. Sure enough there was a program called “ExtractText” that did exactly what I wanted.

Using ExtractText is similar to pdftotext – just pass in the PDF file and the text comes back. Awesome.

Anyway, hats off to Ben Litchfield who wrote the ExtractText example. I rebuilt the ExtactText.java file as a standalone project and packaged it as a JAR.

I’ve attached the JAR and Eclipse project if anyone wants a copy of either.

The JAR

The Eclipse Project

sfWidgetjQueryTimepickr – Symfony timepickr widget

Posted on:Monday, April 6th, 2009 by Ashish Datta

A couple of months ago John Resig posted on his blog about a “new” way for users to pick time.

The component is a jQuery plugin called timepickr and I thought it was particularly neat. Anyway, I finally needed to write a form which had a time component so I figured I’d drop in the timepickr jQuery plugin.

It didn’t look like there was a Symfony Forms widget for it so I whipped one up. You can grab it here.

The only issue with timepickr is that it introduces a ton of dependencies. It requires jQuery, jQuery-ui, jQuery.utils, jQuery.string, and ui.dropslide. Additionally, it needs the dropslide css as well as the timepickr css.

The form widget assumes that you will include jquery-ui by yourself since everyone usually has different naming conventions. It will include the other JS files and CSS files for you.

You can download a package with all of the JS and CSS you need here. Again this DOES NOT include the jQuery-ui stuff. YOU have to include that yourself in your Symfony project as well as on the page that you deploy this widget.

To use it, just drop it in your Symfony project somewhere where classes get autoloaded (projectdir/lib works) and then instantiate a widget with new sfWidgetjQueryTimepickr() . It currently will support all of the timepickr options passed in as widget options (on the constructor). Full documentation for timepickr is here.

Have fun picking time.

Hello Android!

Posted on:Monday, February 23rd, 2009 by Ashish Datta

In the last few weeks the battle and buzz over the smart phone market seems to have seriously intensified.

First there was the usual iPhone buzz, news about the Android powered HTC Magic, the Windows Mobile marketplace, and of course the obligatory ridiculousness at Microsoft.

I’d been considering experimenting with a mobile platform for sometime and finally decided to take the plunge. I decided to give Android a whirl primarily because I don’t have easy access to OSX or Visual Studio and my Java is less rusty than my .NET.

Anyway, getting going with Android was deliciously simple – download the SDK+Emulator and Eclipse plugin and you’re off.

After the necessary “Hello World” application I tried to write something a bit more substantive. Personally, one of the coolest facets of mobile development is the ability for applications to be location aware (GPS). Mix this together with some openly available geo tagged data and the result is probably going to be interesting.

With this in mind, the plan became to mash together Android’s GPS coordinates with flickr’s geotagged photos.

Getting access to Android’s location service is fairly straightforward. You basically register to receive updates either when the device moves a certain distance or on some time interval:

LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
flickrLocationReciever flReciever = new flickrLocationReciever();
locationManager.requestLocationUpdates( locationManager.getProviders(true).get(0),  5, 10, flReciever);

public class flickrLocationReciever implements LocationListener {
  @Override
   public void onLocationChanged(final Location arg0) {
    // do things
   }
}

The biggest “gotcha” with this is that you NEED to remember to modify the default Application security settings to allow you to access the device’s location. In Eclipse, edit AndroidManifest.xml and add “UsesPermission” for the following: android.permission.ACCESS_MOCK_LOCATION, android.permission.ACCESS_COARSE_LOCATION, android.permission.ACCESS_FINE_LOCATION

So on to part II – using the device’s location to pull down Flickr photos. I’d used the Flickr API before so I knew how to do it but I’d never used it from Java. I tried loading the JAR for the flickrj client library but the Android JVM was having some strange issues with it. I was under the impression you can link to external JARs from Eclipse but I may be wrong (anyone?).

Anyway, the Flickr requests were un-authenticated and pretty straightforward so I decided to use Java’s URL class. Accessing sockets was another “gotcha” – Android requires your application to have the “UsesPermission” android.permission.INTERNET to use sockets. The exception when the permission isn’t set is notably cryptic – “unknown error”.

I decided to download all the Flickr photos to the device so that the UX would be generally smoother. This introduced threading to the project so that the UI wouldn’t freeze up while the photos were downloading. Android threads work just like traditional Java threads and the process was generally painless:

private Handler handler = new Handler()
  {
   public void handleMessage(Message msg) {
   // handle the end of the thread
  }
}

Thread t = new Thread()
   {
     public void run(){
     // do stuff
     // let the handler know we are done
     handler.sendEmptyMessage(1);
     }
}
T.start();

With the photos pulled down the final task was displaying them. After poking around the Android documentation I discovered the Gallery widget. It basically allows you to display a set of items in a list and specify a “renderer” for the gallery. I’m not sure if there is a default way to make it “fisheye” (like on an iPhone) but I rolled a quick n dirty solution for that. I also couldn’t get it to look really sexy but that’s also probably possible.

So that’s about it. Here are some screen shots of the application running in the emulator:

And without further a due here is the code as an Eclipse project.
geoflickr

Anyway, before the bashing starts – I know I’m a terrible Java programmer and that this project isn’t really engineered beautifully. It was just supposed to be a way to get my (and anyone else’s) feet wet with Android. Any comments/thoughts/improvements are of course welcome!

Client-side validation for the new Symfony forms with jQuery

Posted on:Friday, January 23rd, 2009 by Hamid Palo
The new Symfony forms are great improvement over the old forms and once you get over the learning curve you can’t imagine life without them. The only problem with them is that they don’t really offer client-side validation (yes, being agnostic when it comes to Javascript libraries is maybe good but come on). There is fortunately a plugin that does client-side validation but it is Prototype-based, and looks a bit clunky.
For those of us using jQuery there was nothing, so we decided to write our own small helper that integrates this jQuery validator with the new forms. It’s nothing fancy, but it does the trick for now, and we may expand it into a full-fledged plugin that does all sorts of crazy things.
Using the helper:
  1. Download and install the jQuery validation plugin.
  2. Download the helper and put it in lib/helper/jQueryValHelper.php
  3. Include the jQueryVal helper.
  4. To enable the helper for a specific form:
    <?php echo jquery_val_form_tag($form, array(‘action’ => url_for(“@register) ))?>

That’s it.

The validator currently supports email, min and max length validation. The only required option is action, the other options you can pass it are:

  1. error_placement: Change where the errors are rendered, for example:
    'error_placement' => 'error.prependTo(element.parent().next())'
  2. error_element: Change the element used to render the errors, default is label.

All other options you pass are added to the form as attributes.

JSON explorer for Firebug!

Posted on:Thursday, December 18th, 2008 by Ashish Datta

As Firefox plugins go, Firebug is definitely one of my favorites. It has saved me and the rest of the Setfive team dozens of development hours. One of the nicest features of Firebug is the NET panel. The NET panel allows a developer to monitor HTTP requests that Firefox is making during the course of a page’s execution. This is particularly useful to AJAX heavy applications because it allows a developer to easily debug XHR requests and responses.

Although this is great, the NET panel is severely lacking when it comes to dealing with JSON responses. Since JSON must be a legal JavaScript string, it can’t contain any line breaks. As a consequence, debugging long JSON strings is extremely painful.

This issue has been on the Firebug TODO list for some time. I figured this would be a good place to jump into the Firebug codebase. I dropped an email to the Firebug working group and received some great feedback. Honza gave me a template extension to extend the NET panel and provided some great insight and advice on implementing a JSON viewer.

After a couple of weeks of intermittent work, the JSON-Viewer extension is ready to play with. Honza has committed the code into the Firebug 1.4+ branch so if you grab a new build you’ll be able to use the JSON viewer.

Screenie:

Read more at Honza’s blog post