jQuery UI confirm

March 21st, 2011 by Ashish Datta

I was looking around earlier for a jQuery plugin to allow me to use jQuery UI’s dialog() widget to popup a confirm dialog. Didn’t have any luck finding one so I whipped something up. It’s not pretty but it works. You could even go as far as to overload window.confirm() but thats probably a bad idea.

jQuery.confirm = function(options){

	var opts = jQuery.extend( { message: "", ok: function(){}, cancel: function(){ } }, options );

	jQuery("
" + opts.message + "" + "
").dialog({ autoOpen: true, modal: true, autoOpen: false, resizable: false, draggable: false, title: "", width: "400px", buttons: { "Cancel": function(){ opts.cancel.call( this ); }, "Ok": function(){ opts.ok.call( this ); } } }).dialog("open"); }; // use it jQuery.confirm( { "message": "Are you sure?", "ok": function( ){ $(this).find(".loader:first").show(); // do stuff $(this).dialog("close"); }, "cancel": function( ){ $(this).dialog("close"); } });

Drupal 7: Batch insert nodes with Drush

February 9th, 2011 by Ashish Datta

Well D7 has been out for a little while now and we finally got a chance to use it on a site this week.

Anyway, this site is one of the heavier Drupal sites we’ve done and it involved loading ~200+ nodes of data just to set things up. This presented two problems, how to batch load data and then how to load custom content types with several custom fields.

The Drupal module documentation has example code for adding a node with drupal_exeucte here but it doesn’t deal with how to set custom fields on your content type. On top of this, drupal_execute has been renamed to drupal_form_submit in Drupal 7 and the function signature has changed a bit.

Anyway, I dug around a bit and finally managed to get this working. You’ll obviously need Drush installed for the following code to work but you could rip it out and use it outside a Drush command. I was looking to basically replicate the “load-data” task from Symfony so that I could seed my Drupal database with Nodes at any point so I chose to make this a Drush command.

Here’s what you need:

- You’ll need a module to hold the Drush task. I used Module Builder to generate my scaffolding.
- Create a file named [modulename].drush.inc in your module directory
- Here is the code I’m using for [modulename].drush.inc Replace “cm” with the name of your module:


/**
* Implementation of hook_drush_command().
*/

function cm_drush_command() {

        // callback is the function that will be called when the command is executed
	$items['load-rep-data'] = array(
	    'callback' => 'cm_load_rep_data',
            'description' => 'Loads the representative data.',
            'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
	);

	return $items;
}

function cm_load_rep_data( ){
   // you need this to autoload the functions to create nodes
   module_load_include('inc', 'node', 'node.pages');

  // do some business logic to load your data from where it is
  foreach( $arr as $res ){

    // define the custom node type
    $node = array('type' => 'representative');

   // set up the form array
   $form_state = array();

   // set the title of the node
   $form_state['values']['title'] = $res["title"];

   // set a custom field that is a text type
   $form_state['values']['field_first_name']['und']['0']['value'] = $res["first_name"];

   // set a long text field and enable full_html - NOTE you'll need to allow anonymous users to use this for Drush to work
   $form_state['values']['body']['und']['0']['format'] = 'full_html';
   $form_state['values']['body']['und']['0']['value'] = $res["bio"];

  // set some custom select fields
  $form_state['values']['field_house_committees']['und'][ 0 ] = 34;
  $form_state['values']['field_house_committees']['und'][ 0 ] = 37;

  // can't leave this out or the form wont save
  $form_state['values']['op'] = t('Save');

  // actually try and "submit" the form
  drupal_form_submit('representative_node_form', $form_state, (object)$node);

  // printing from Drush is easy
  drush_print( $res["title"] );
  }
}

Thats about it.

With Firebug, it’s really easy to see the field names and the values that you can set by just looking at a form to create whatever type of node you want.

drupal_form_submit can also be used to “submit” any other type of form in Drupal.

An open question is how to “fill out” an ImageField field via the command line since nothing is actually going to be uploaded.


Getting an extra ‘Invalid’ or other error on your symfony form?

January 27th, 2011 by Matt Daum

On a project I’m working on I came across the following problem: we had a email field that we needed to be unique in our system, but we also made sure that it matched a confirm email field. A snippet of our form looks like this:

  public function configure()
  {
     $this->setWidgets( array(
        'email'         => new sfWidgetFormInputText()
        'confirm_email' => new sfWidgetFormInputText()
      ));

      $this->setValidators(array(

      'email'=>         new sfValidatorAnd(
                          array(
                              new sfValidatorEmail( array('required' => true) ),
                              new sfValidatorDoctrineUnique(
                                  array('throw_global_error' => true, 'model' => 'sfGuardUser', 'column' => 'username'),
                                  array('invalid' => 'Sorry! A user with that email address already exists.')
                              )
                          )),
        'confirm_email' => new sfValidatorEmail( array('required' => true) )

      ));

      $this->validatorSchema->setPostValidator(
        new sfValidatorSchemaCompare('password', '==', 'confirm_password')
      );
  }

When we submitted an email that was already in the system we got back two errors:

  • Sorry! A user with that email address already exists.
  • Invalid.

For a while I thought is there some extra validator somewhere that I left on? Where is this invalid coming from? It ended up being due to the way the validators work. If a validator throws an error it doesn’t return that validator’s value. So by the time it gets to the sfValidatorSchemaCompare post validator the value of `email` is null and `confirm_email` has the value you input, thus the seemingly extra ‘Invalid’ message.

This can be fixed easily with a sfValidatorCallback instead of the sfValidatorSchemaCompare. Here is the fix:

  public function validateConfirmEmail( $validator, $values ){

    if($values['email']&&$values['email']!=$values['confirm_email'])
    {
      throw new sfValidatorError($validator, 'Please confirm your email, currently they do not match!.');
    }

    return $values;
  }

This way if the email is blank it doesn’t both making sure that the `email` matches the `confirm_email`. You don’t need to worry about a person just passing two blank emails as the earlier validator(the sfValidatorEmail requires it to be there and valid).

If you are getting an extra validation error, check your postValidators and how the values get to them.


Received problem 2 in the chunky parser

December 26th, 2010 by Ashish Datta

I was using cURL in PHP to POST some data to a URL earlier tonight and ran into this problem.

With VERBOSE on cURL was erroring with the following error:

"Received problem 2 in the chunky parser"

After some Googling it turns out this is a problem with how some servers respond with chunked encoding.

A simple fix for this is to set the HTTP version cURL is using to 1.0:

curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 )

It’s not pretty but hey it works!


Changing a Doctrine connection with the same name in single instance

December 6th, 2010 by Matt Daum

On one of our projects that we use multiple connections that are defined at run time we recently were generating reports that required us to change a specific connection multiple times in a single run.    We noticed that even though we would define a new connection, it would not throw any errors but just continue to use the originally defined connection.  Here is how we were doing the connections:

$databaseManager = sfContext::getInstance()->getDatabaseManager();
$manager=Doctrine_Manager::getInstance();
$newConn = new sfDoctrineDatabase(array('dsn'=>'XXX','name'=> 'ExampleName'));
$newConn->connect();
$databaseManager->setDatabase('ExampleName',$newConn);

If you called the code above once, it would connect properly to the given DSN. However if you then called it a second time with a new DSN, it would not error and would simply just remain connected to the first DSN. After hunting around a bit it was the problem that Doctrine wasn’t assigning the new connection as the old connection was still open. To get around this we updated the code to the following:

$databaseManager = sfContext::getInstance()->getDatabaseManager();
$manager=Doctrine_Manager::getInstance();

// If the Doctrine Manager has the connection already close it so the new connection can be established
if($manager->contains('ExampleName'))
        $manager->closeConnection($manager->getConnection('ExampleName'));
$newConn = new sfDoctrineDatabase(array('dsn'=>'XXX','name'=> 'ExampleName'));
$newConn->connect();
$databaseManager->setDatabase('ExampleName',$newConn);

You need to first check to see if the Doctrine Manager has the connection, as if you try to get a connection that doesn’t exist, it will throw an exception.

Hope this saves you some time!


Security questions, re-imagined

November 10th, 2010 by Ashish Datta

Earlier today we were discussing implementing “security questions” for a client of ours. The client felt that we should implement security questions so that users would have to answers one or more questions before taking certain actions on the site.

For those who aren’t familiar with the concept, some applications will ask users “security questions” at certain touchpoints in the application. The questions have been previously answered by the user and usually ask somewhat personal information like “what street did you grow up on?”, “what is the name of your favorite pet?”, “what was your high school’s mascot?”

As several security researchers have pointed out, the answers to these types of questions can be easily derived from a mix of a user’s social profiles and some social engineering. One of the most famous examples of this was the compromise of Sarah Palin’s email account during the lead up to the 2008 presidential campaign.

At the gym earlier, I started wondering about this problem and stumbled across what might be the basis of a novel solution.

The issue with the current solution is that the lexicon of questions asked are always pieces of personal information that users typically will share with the world. The obvious solution would be asking extremely personal questions like “who was your first kiss?”, “have you ever stolen something”, and so on. Unfortunately, these will undoubtedly make users uncomfortable and force the application to store extremely sensitive information.

What we’re really looking for is innocuous personal questions that users will not typically broadcast via social networks and also difficult to social engineer. With this in mind, my solution would be to ask questions that users don’t normally think about but when taken together, are identifiable enough to prove that a user is in fact genuine.

Here’s a few I thought of:

- Do you signal a “3″ with your three index fingers or with your thumb and two index fingers? (For those who haven’t seen it, this is discussed at length in The Inglorious Bastards)
- Do you tie your shoes with “bunny ears” or with a loop?
- What knot do you use to tie your necktie?
- What type of seafood are you allergic to?
- What brand of refrigerator do you currently own?

Obviously, some of these are multiple choice questions which makes a probabilistic attack easier but by using a combination of multiple choice and open ended I think you could end up with a pretty strong solution.

Anyway, I’d love to hear any feedback and other good questions if anyone comes up with them.


iPhone style checkboxes for Symfony

October 13th, 2010 by Ashish Datta

No one worry, I did in fact survive my birthday and subsequent party!

Anyway, I was poking around for some cool UI elements for checkboxes and stumbled across this neat jQuery plugin – http://github.com/tdreyno/iphone-style-checkboxes Basically, what it does is converts checkboxes into iPhone style toggles.

Check out a demo at http://tdreyno.github.com/iphone-style-checkboxes/

This is for a symfony project (shocker!), so I figured I’d roll it into a widget and share.

You’ll need to download and include the JS+CSS+images for the plugin yourself and then copy the following code into your project:


class sfWidgetFormInputiPhoneCheckbox extends sfWidgetFormInputCheckbox {

	public function __construct($options = array(), $attributes = array())
	{

		$this->addOption('checked_label');
        $this->addOption('un_checked_label');

		parent::__construct($options, $attributes);
	}

	public function render($name, $value = null, $attributes = array(), $errors = array())
	{
		$str = parent::render( $name, $value, $attributes, $errors );

		$checkedLabel = $this->getOption("checked_label");
        $uncheckedLabel = $this->getOption("un_checked_label");
        $id = $this->generateId($name);

		$str .= <<

		  $(document).ready( function(){

                $('#$id').iphoneStyle({
                    checkedLabel: '$checkedLabel',
                    uncheckedLabel: '$uncheckedLabel'
                });

		  });
		
EOF;

		return $str;
	}

}

Using it is straightforward:

    $this->setWidgets(array(
      'show-upcoming-events-nav' => new sfWidgetFormInputiPhoneCheckbox( array("checked_label" => "on", "un_checked_label" => "off") ),
    ));

Streaming Foursquare checkins with Google Maps

September 13th, 2010 by Ashish Datta

This Saturday was the second annual Redline Challenge which is a bar crawl from Downtown Crossing to Davis Square that loosely tracks the MBTA Redline.

This year, we decided to use Foursquare to allow the website to track the position of several of the participants on the challenge. Foursquare natively allows you to track your checkin history with private URLs. Currently, they support a handful of formats with KML being the most interesting for our purposes. You can find your private URLs by navigating to http://foursquare.com/feeds/

We used the Google Maps API along with the KML stream from Foursquare to dynamically place markers on the map as different users checked in to different venues.

Here is the PHP we used to pull back the KML feed, transform it to JSON, and spit it back to our jQuery on the client side:

$xml = simplexml_load_file( "http://feeds.foursquare.com/history/myurl.kml" );
$arr["a"] = $xml->Folder;
$xml = simplexml_load_file( "http://feeds.foursquare.com/history/ackleysurl.kml" );
$arr["m"] = $xml->Folder;

echo json_encode( $arr );

Pretty straight forward. Here is the jQuery code on the client side to add markers to the map:

       $.getJSON( "location.php", {}, function(data){

    	   data.a.Placemark = data.a.Placemark.reverse();

         var hasStarted = false;
         var barIndex = 1;

         $.each( data.a.Placemark, function(i, val){

               if( val.published.indexOf("Sat, 11") == -1 ){
                    return true;
               }

               if( !hasStarted && val.name == "Setfive Consulting" ){
                  hasStarted = true;
               }else if( !hasStarted ){
                  return true;
               }

               var latLng = val.Point["coordinates"].split(",");

               var point = new GLatLng( latLng[1], latLng[0] );

               var marker = new GMarker(point);

               marker.bindInfoWindowHtml( "
" + barIndex + ". " + val.name + "
" ); map.addOverlay(marker); latLngList.push( point ); if( i == data.a.Placemark.length-1 ){ map.setCenter(point, 14); $(marker).click(); marker.openInfoWindowHtml( "
We are at " + barIndex + ". " + val.name + "
" ); } barIndex++; }); var polyline = new GPolyline( latLngList, "#ff0000", 5 ); map.addOverlay(polyline); latLngList = []; data.m.Placemark = data.m.Placemark.reverse(); var blueIcon = new GIcon(G_DEFAULT_ICON); blueIcon.image = "http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png"; markerOptions = { icon:blueIcon }; barIndex = 1; $.each( data.m.Placemark, function(i, val){ if( val.published.indexOf("Sat, 11") == -1 ){ return true; } var latLng = val.Point["coordinates"].split(","); var point = new GLatLng( latLng[1], latLng[0] ); var marker = new GMarker(point, markerOptions); marker.bindInfoWindowHtml( "
" + barIndex + ". " + val.name + "
" ); map.addOverlay(marker); barIndex++; latLngList.push( point ); }); var polyline = new GPolyline( latLngList, "#001299", 5 ); map.addOverlay(polyline); })

That’s about it.


ahDoctrineEasyEmbeddedRelationsPlugin and Composite Primary Keys

September 3rd, 2010 by Matt Daum

We’ve been working on a project in which a bunch of the tables had composite primary keys.  Often we wanted to embed these tables in other forms.  ahDoctrineEasyEmbeddedRelationsPlugin is a great plugin for managing embedded forms with Doctrine and Symfony.  It lets you easily let users add multiple new relations and delete previous ones.   However, it didn’t really support composite keys.   We also wanted to be able to expose the primary keys rather than unsetting them from the form(so that the relation is automatically declared).  This was a problem as we needed to be able to select at least one of the primary keys.  Here is an example where we wanted to let the user pick one of the primary keys:

User:
  columns:
     first_name:
        type: string(16)
Product:
   columns:
      name:
         type: string(32)
UserProduct:
   columns:
      user_id:
         type: integer
      product_id:
         type: integer
        price:
          type: decimal
    relations:
       User:
          local: user_id
          foreign: id
       Product:
         local: product_id
         foreign: id

In this case there are Products and Users. A Users can have a products and specify how much each costs. When you are adding products to a user, you would want to be able to select which product you are adding in the embedded form. This is where our problem was, with the plugin as of version 1.4.4 you couldn’t tell it not to unset the primary keys when it embedded the form. We did a checkout of the plugin from SVN and modified it a bit. It now has and additional parameter: newFormUnsetPrimaryKeys . This will make it so the plugin will not unset the primary keys on a new form if you set it to true (it defaults to false).

We also found that the plugin had hard coded a couple of places findOneById which required the primary key to be called `id`. We’ve updated this to use the Doctrine method getIdentifierColumnNames() to get the primary keys.

We only applied to be developers on this script, so are currently waiting on it to be packaged and released, however if you want our updated just do a svn checkout of the plugin and you will be all set!

Let us know if you have any questions on it!


UPDATED: New Facebook Phonebook Script

July 19th, 2010 by Ashish Datta

I realized this morning that Anonymous Coward’s Facebook Phonebook Greasemonkey script broke awhile back so I decided to rewrite it from scratch.

The original instructions for how to install the script are available here.

I updated the original Userscripts page with the new script so you can download it here.

Once again, this probably breaks your Facebook TOS so I can’t vouch for the safety of your account if you do decide to do this.