Symfony2: Using kernel events like preExecute to log requests

A couple of days ago, one of our developers mentioned wanting to log all the requests that hit a specific Symfony2 controller. Back in Symfony 1.2, you’d be able to easily accomplish this with a “preExecute” function in the specific controller that you want to log. We’d actually set something similar to this up and the code would end up looking like:

<?php

public function preExecute(){
  $this->jsonVariables = strlen($this->getRequest()->getContent()) 
                           ? json_decode( $this->getRequest()->getContent(), true ) : array();
      
   if( strlen(trim($this->getRequest()->getContent())) && $this->getUser()->getUserId() ){
      $uid = $this->getUser()->getUserId();
      $log = new JsonApiLog();
      $log->setUserId( $uid );
      $log->setRequestBody( $this->getRequest()->getContent() );
      $log->save();
   }
      
}

Symfony2 doesn’t have a “preExecute” hook in the same fashion as 1.2 but using the event system you can accomplish the same thing. What you’ll basically end up doing is configuring an event listener for the “kernel.controller” event, inject the EntityManager (or kernel) and then log the request.

The pertinent service configuration in YAML looks like:

    ctbe.apirequest_listner:
        class: CT\BEBundle\Event\ApiControllerRequest
        arguments: [@kernel]
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onControllerRequest }

And then the corresponding class looks something like:

<?php

namespace CT\BEBundle\Event;

use CT\BEBundle\Entity\ApiRequest;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Kernel;

class ApiControllerRequest {
    
    private $kernel;
    
    public function __construct(Kernel $kernel){
        $this->kernel = $kernel;
    }
    
    public function onControllerRequest(FilterControllerEvent $event){
        
        $controller = $event->getRequest()->attributes->get('_controller');

        if( count(explode("::", $controller)) == 1 ){
            return;
        }
        
        list($className, $methodName) = explode("::", $controller);
        $className = explode("\\", $className);
        $className = $className[count($className) - 1];
        
        if( strpos($className, "Api") === false ){
            return;
        }

        $user = $this->kernel->getContainer()->get('security.context')->getToken()->getUser();
        
        $req = new ApiRequest();
        $req->setUser($user);
        $req->setRequest( $event->getRequest()->getContent() );
        $req->setUrl( $event->getRequest()->getRequestUri() );
        
        $this->kernel->getContainer()->get("doctrine")->getEntityManager()->persist($req);
        $this->kernel->getContainer()->get("doctrine")->getEntityManager()->flush($req);
    }
}

And thats about it.

Happy 4th of July!

Hope everyone is having a fantastic 4th of July. Make sure to drink some brews and eat some BBQ!

PHP: How do you evaluate PHP skill?

We’re always on the hunt for talented LAMP developers and as a consequence we end up evaluating a decent amount of fairly diverse PHP code. We always ask potential employees for a code sample so that we can get a sense of their style and generally make sure they have their heads screwed on right. Because of this, we’ve been evaluating PHP samples from everything from Drupal modules, to batch processing scripts, and even “hardware hacks”.

During this process, one of the issues we’ve had is coming up with an objective rubric to evaluate the relative skill of a PHP developer. Although there are several broad criteria for evaluating code, I’ve been interested in coming up with PHP-centric benchmarks since they’re more directly applicable. Here’s a list of criteria that we’ve been working on to help us identify how familiar an engineer is with PHP.

Negative Signals

Unfortunately, it’s sometimes easier to spot negative signals so here are a few PHP specific “code smells” we’ve identified.

Re-inventing standard library functions

Often, inexperienced engineers won’t search for standard functions that’ll do exactly what they’re looking for. Not always a bad thing but it’s a sign of inexperience. An example would be:

<?php

function getDaysArray(){
  $dayOfTheWeek = array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");
  
  $arr = array();
  foreach($dayOfTheWeek as $day){
    $arr[$day] = $day;
  }

}

/** VS. **/

function getDaysArray(){
  $dayOfTheWeek = array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");
  return array_combine($dayOfTheWeek, $dayOfTheWeek);
}
Not really understanding the ORM (or SQL)

This one isn’t really PHP specific but we’ve noticed it a couple of times anyway. We’ll often see code that looks something like:

<?php

function getActiveUsersOfAge(){

  $em = $this->getContainer()->get('doctrine')->getEntityManager();
  $users = $em->getRepository("Acme:User")->createQueryBuilder("u")->getQuery()->getResult();

  $arr = array();
  foreach( $users as $us ){
    if( $us->getIsActive() && $us->getBirthdate() < "1991" ){
      $arr[] = $us;
    }
  }

  return $arr;
}

As you can see, the code returns all the results and then evaluates the criteria as opposed to passing the selection criteria to the ORM or SQL.

Everything is a global

Due to PHP’s global keyword it’s unfortunately really easy to throw encapsulation to the wind and just make everything a global. Because of that, we’ve seen code that looks like:

<?php

$someListOfData = "";
$someResult = null;

function sumTheList(){
  global $someListOfData, $someResult;
  // do stuff  
}

function writeTheResult {
  global $someListOfData, $someResult;
  // do some other stuff
}

Positive Signals

What we look for next is usually positive signals that an engineer is generally familiar with PHP. These are generally things you’d pick up after you’ve written a fair amount of PHP.

Has implemented __toString() somewhere

I know this one will be controversial, but my sense is that if an engineer implements __toString() somewhere in PHP they probably have a decent familiarity with the language since its something you have to “seek out”. A canonical example would be something like:

<?php

class User {
  private $firstName;
  private $lastName;


  public function __toString(){
    return $this->firstName . " " . $this->lastName;
  }  
}
Uses output buffering

Output buffering is a bit exotic but it’s indispensable when building web apps without a framework. It also certainly demonstrates a level of familiarity with PHP. A good example would be capturing output from a template and returning it inside some JSON:

<?php

ob_start(function($output){
  return json_encode( array("html" => $output) );
});

require "someTemplateFile.html";

ob_end_flush();

Voodoo Positive Signals

Finally, the last couple of things we’ve been looking for are “exotic” techniques that really demonstrate that someone “gets” PHP. Granted, some (most?) of these are bad ideas in production they do convey a certain level of understanding.

Classes that implement the ArrayAccess interface

Since PHP relies so heavily on arrays, building classes that implement the ArrayAccess interface makes them work more naturally in PHP and definitely demonstrates a strong level of familiarity with the language. An example would be:

<?php

class FormInput implements arrayaccess {

    private $values = array();

    public function __construct($values) {
        $this->values = $values;
    }

    public function offsetSet($offset, $value) {

    }

    public function offsetExists($offset) {
        return isset($this->values[$offset]);
    }

    public function offsetUnset($offset) {
        unset($this->values[$offset]);
    }

    public function offsetGet($offset) {
        return isset($this->values[$offset]) ? htmlentities($this->values[$offset]) : null;
    }
   
}

$form = new FormInput($_REQUEST);
echo $form["username"] . "\n";
Using __set, __get, or __call

Although, using any of these in production is questionable at best, they undeniably do convey a sense that whoever used them knows their way around PHP. An example (from the documentation) would be:

<?php

// From http://www.php.net/manual/en/language.oop5.overloading.php#object.call

class MethodTest
{
    public function __call($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }

    /**  As of PHP 5.3.0  */
    public static function __callStatic($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling static method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');

Anyway, like everything I’d take this list with a big grain of salt. We’d also love any input or feedback.

Bootstrap: Customize the typeahead() render method

Earlier in the week, I was looking to customize how the Bootstrap typeahead() plugin was rendering the autocomplete options. Surprisingly, looking at the options listed on the plugin there is no way to specify a custom renderer function. Poking around a bit, I ran across this pull request on GitHub it looks like changes to the typehead() plugin have been tabled since it’s going to be replaced in Bootstrap 3.0 anyway.

I didn’t really want to customize our version of Bootstrap for a single page so I went on the hunt looking for a way to customize the renderer without modifying the plugin. Looking at how the typeahead() plugin is instantiated I noticed that a reference to the “Typeahead()” object with the render() method is actually stored using data() for the element it’s activated on. Because of that, it’s actually relatively straightforward to just overwrite the render() method on the specific element that you’ve activated typeahead() on.

The code I ended up with basically looks like:

<input type="text" autocomplete="off" id="typeAheadTest" />

<script>
$(document).ready(function(){

$("#typeAheadTest").typeahead({source: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]});

$("#typeAheadTest").data("typeahead").render = function (items) {

  var that = this;
  items = $(items).map(function (i, item) {
    var itemClass = (item == "Sunday" || item == "Saturday") ? "weekend" : "weekday";
    i = $(that.options.item).attr('data-value', item).attr("class", itemClass);
    i.find('a').html(that.highlighter(item))
    return i[0]
  })

  items.first().addClass('active')
  this.$menu.html(items)
  return this

};

});
</script>

Anyway, just a fun tidbit. Questions or comments welcome as always.

Symfony2: usort() Array was modified by the user comparison function

Earlier this week we were repeatedly getting notifications about a “usort() Array was modified by the user comparison function” warning for one of our new Symfony2 projects. The weird thing was the sort function was relatively straightward and looked something like:

<?php

usort($arr, function($a, $b){
  return strcmp($a->getBrand()->getName(), $b->getBrand()->getName()); 
});

Obviously not modifying the array. Anyway, Daum dug up this StackOvervlow thread which suggested that using introspection methods silently modify the array and trigger the warning but I’m clearly not using any of those either.

After some more poking around, we ran across a Doctrine bug specifically mentioning the usort issue. It turns out, because of how Doctrine’s lazy loading functionality works if the usort callback function causes Doctrine to lazy load it’ll silently modify the array and cause that warning. Great, so how do you fix it? It’s actually pretty straightforward, you just need to force the lazy loading before sorting the collection. I ended up with something like:

<?php

foreach($arr as $ab){
  $n = $ab->getBrand()->getName();
}

usort($arr, function($a, $b){
  return strcmp($a->getBrand()->getName(), $b->getBrand()->getName()); 
});

Anyway, fun fact of the day. Questions and comments always welcome.