Blog

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.


Doctrine Multiple Connections with Symfony Web Debug Toolbar

July 8th, 2010 by Matt Daum

In April I wrote about using Doctrine with multiple connections for specific table models.  This worked really well, except Symfony’s web debug toolbar would not show any SQL queries that were not defined in the databases.yml file.  This of course made it quite difficult to debug many queries, as the query logs show the queries before the parameters are inserted, for example:

SELECT a.id, a.title FROM posts a WHERE id = ?

The web debug toolbar however shows them with the parameters in place. This makes it a ton quicker to debug as you can see the parameters in place, as well as copy and paste the query straight into the SQL client to see the raw results. After a few months and a project becoming much more complex it was necessary to see the queries. I looked up how sfWebDebugPanelDoctrine gets the queries and found:

  protected function getDoctrineEvents()
  {
    $databaseManager = sfContext::getInstance()->getDatabaseManager();

    $events = array();
    if ($databaseManager)
    {
      foreach ($databaseManager->getNames() as $name)
      {
        $database = $databaseManager->getDatabase($name);
        if ($database instanceof sfDoctrineDatabase && $profiler = $database->getProfiler())
        {
          foreach ($profiler->getQueryExecutionEvents() as $event)
          {
            $events[$event->getSequence()] = $event;
          }
        }
      }
    }

    // sequence events
    ksort($events);

    return $events;
  }

So the sfDatabaseManager would manage all the connections and return which ones to pull queries off of. I looked at it a bit and saw that it has setDatabase which sets the databases it has registered. Since it requires you give it a sfDatabase as a parameter I had to update the way we connect the databases a bit so we could pass them to it. The new version is below:

          $databaseManager = sfContext::getInstance()->getDatabaseManager();
          $newConn=new sfDoctrineDatabase(array('name'=>'NewConnectionName','dsn'=>$databaseString));
          $newConn->connect();
          $databaseManager->setDatabase('NewConnectionName',$newConn);

Now you will now see the queries in the web debug toolbar.


QR Bookmarklet

June 13th, 2010 by Ashish Datta

I got tired of having to find the same website (mostly recipes) on my phone after looking at them on my workstation or laptop so I decided to whip together a bookmarklet to throw a Google powered QR code on any page.

The bookmarklet will just slap a QR code image with the current page’s URL (window.location) so that you can open the page on your phone. ps. Barcode Scanner for Android will automatically open the URL in a browser.

Without further ado, QR Code Bookmarklet


jQuery.trigger weirdness

June 10th, 2010 by Ashish Datta

Earlier today, I was trying to use jQuery to trigger the submission of a form after a radio button was clicked. The form tag looked something like:

...form..

So for a regular submit button:


Everything works fine, you’ll see the alert() and the form won’t submit because of the return false.

I ran into issues when I tried to trigger() the submit event with jQuery. I was trying to trigger the submit() event on the form via jQuery. The problem I ran into, was that the saysomething() function was getting called, but the “return false” seemed to have no effect.

The final form looked something like:

For some reason, if you submit the form via a jQuery trigger the form submits even though saysomething() gets called. I’m not sure if this is the expected behavior but it was certainly something of a shock. Anyway, a live version of the form is running here.


WeGov.com out the door

May 27th, 2010 by Ashish Datta

Wow two in one day! Well it has taken some time, but along with the WeGov team we launched WeGov.com this morning.

From the site’s about us:

WeGov.com is the most comprehensive, nonpartisan platform for civic engagement, political participation, and organizational activism. WeGov provides a free and open environment for groups, campaigns, and like-minded citizens to organize themselves, easily reach elected officials, and magnify their influence as a VerifiedVoter™.

We’re really excited to see where WeGov goes and how it will reshape the online political landscape. For WeGov media and press inquiries, please email info@wegov.com. Otherwise, to get in touch with us shoot off an email to contact@setfive.com.

Hope everyone has a great Memorial Day weekend.


ForexTV.com Goes Live

May 27th, 2010 by Matt Daum

We’re proud to announce the relaunch of of a partners website: http://www.forextv.com.  The website delivers Forex news and video along with other Forex resources.  The website has been rebuilt on the Symfony framework.

In the coming weeks we will be rolling out many new features, including several social components.  Keep checking back and let us know how we are doing!


Run jQuery each() serially

May 18th, 2010 by Ashish Datta

jQuery.each() is pretty sweet but earlier today I wanted to run some animations across a set of three elements and since the animate() calls are non-blocking everything was happening at the same time. What I wanted to do was have the functions execute in a serial fashion (1 after the other).

I poked around and it doesn’t look like there’s a native way to do this. After a bit I decided to just whip something up and see how it works. Here’s what I had originally:

$("#splashStream .snippetbox").each( function(index){
	$(this).animate( {opacity: 0}, 1000, function(){
		$(this).html( $("#hiddenSplashDiv .snippetbox:eq(" + index + ")").html() );
		$(this).animate( {opacity: 1}, 2000 );
	});
});

That ran fine but everything happened at the same time. The modified serial code looks like:


                  var hasCallbackCompleted = [ true ];
                  $("#splashStream .snippetbox").each( function(index){

                      var f = arguments.callee;
                      var args = arguments;
                      var t = this;

                      if( !hasCallbackCompleted[ index ] ){
                        window.setTimeout( function(){ f.apply(t, args); }, 5 );
                        return true;
                      }

                      hasCallbackCompleted[ index + 1 ] = false;
                      $(this).animate( {opacity: 0}, 1000, function(){
                          $(this).html( $("#hiddenSplashDiv .snippetbox:eq(" + index + ")").html() );
                          $(this).animate( {opacity: 1}, 2000, function(){
                            hasCallbackCompleted[ index + 1 ] = true;
                          });
                      });

                  });

Basically, what it does is after the first element, the code will delay execution of the each() function until the hasCallbackCompleted flag is set for the correct element.


jQuery blank() modified for password fields

April 28th, 2010 by Ashish Datta

We’ve been using Jeff Hui’s very awesome jquery.blank plugin for sometime over at Setfive HQ. What blank() is allow you to basically move the labels for text inputs into the input themselves (to save space). We use this technique frequently for login boxes in headers since it’s easier not to have to stick in labels next to text boxes.

The problem is, you can’t use blank() on a password field since a password field won’t display clear text (obviously). To get around this, I’ve always manually stuck in a “shadow” text box next to the password field and toggled the text box or password box in order to make blank() work correctly.

Anyway, I finally got tired of doing this so I decided to patch the plugin to do this automatically. Jeff incorporated the code back into blank() and it’s available on GitHub here.

Happy coding.


Using Doctrine Result Cache With Two Deep Relations

April 28th, 2010 by Matt Daum

Recently we’ve been working on a new project that requires caching of both views and database queries. One of the problems I came across I wanted to Result Cache an query I was using for a pager. This caused a couple of problems, one being I needed to be able to clear the cache by its prefix so we would never have a stale cache. Doctrine has a built in deleteByPrefix call for this, however on a pager how do I get it so that it will use a result cache, but still use different indexes for different pages? The following code would not work:

$this->createQuery('sc')
           // A couple of complex joins here, etc
            ->where('sc.video_id = ?',$id)
            ->orderBy('sc.created_at DESC')
            ->useResultCache(true,sfConfig::get('app_comment_cache'),'comment_index');

Well here the problem is everything is being cached as as the ‘comment_index’ cache, so if you passed that query to a pager, and told it to be on the second page, it’d see the ‘comment_index’ cache exists, and use that. A simple way around this is:

  // Query build...
 ->useResultCache(true,sfConfig::get('app_comment_cache'),'comment_index_'.$page);

In this example page is the parameter you are passing the query and the Doctrine pager to tell it what page cache to look at.

Then a very weird problem was occurring, I was getting more queries if I USED the cache than if I didn’t. Very weird. It seemed that one of the joins object did not seem to be getting stored in the cache. The join looked something like this:

  $this->createQuery('sc')
         ->leftJoin('sc.User u')
         ->leftJoin('u.Profile p')
         //.... more joins etc

The problem was the profile object was not getting stored in the result cache and thus causing a query each time it was called from the user object. After much hunting around, a long time in #doctrine, and a few leads from a couple of people, it turns out, by default, Doctrine will only serialize the immediate relation to the main object (in this case ‘sc’). However, you can make it so that it will serialize objects further down the line by overriding the function serializeReferences to return true in the class you want to serialize references from. In my example this is the User class. Since our application will never only need the ‘User’ class to be serialized on a result cache I completely overrode the function and made it always return true

class User extends BaseUser{
  public function serializeReferences($bool=null)
  {
    return true;
  }
}

Of course you can set this on a per object instance via $user->serializeReferences(true). Overriding the method the way I did you need to be careful as you could potentially waste a ton of storage space in your result cache.

Hope this saves someone some head banging and confusion on how using a cache could actually cause more queries if not stored properly.


Doctrine Multiple Connections and Specific Tables

April 7th, 2010 by Matt Daum

Recently for a project we had the following situation: Users have their own specific databases, however each database has the same schema. Since there are an unlimited number of databases this prevented us from using databases.yml to define which tables need to go to which databases. The user’s database connection would be defined at run time and we needed only certain tables to be bound to that connection. A bunch of googling turned not much up, mostly talking about defining it in the databases.yml file. After a little bit of searching through some of the Doctrine documentation I came across bindComponent. This allows you to tell a model to use a specific connection. For example:

$newConn = Doctrine_Manager::connection('mysql://myuser:mypassword@somehost/somedatabase','UsersConnection');
$manager=Doctrine_Manager::getInstance();
$manager->bindComponent('SomeModel','UsersConnection');

The above would bind the model ‘SomeModel’ to the connection ‘UsersConnection’. To make this so that it is automatically done each time it is executed a good place to add it is a custom filter.

Also if you plan on storing the user’s database passwords it is a good practice to encrypt them. Look into possibly using the class sfCrypt for this.