Automating timestamps with Doctrine ORM

The Doctrine ORM includes a robust Event system enabling timestamp fields to be set automatically without any explicit methods calls during object instantiation. This also works great when utilising the many smart RESTful design patterns for Symfony, Laravel and other frameworks which can implement Doctrine.

To have Doctrine recognise event hooks the HasLifecycleCallbacks() annotation should be added to the Entity class:


/**
* @HasLifecycleCallbacks()
* @Entity
*/
class User {
}

Typically Doctrine will be imported to the file as something like @ORM, so the full annotation will be:


/**
* @ORM\HasLifecycleCallbacks()
* @ORM\Entity
*/
class User {
}

Now as the columns to the database that will be utilised (either add to Database manually, using the relevant Doctrine console commands, or even better, a Doctrine Migration):

All persisted objects of this class will now have a timestamp automatically set when created, updated or deleted.

For a more complete example of a resulting Entity class (with typical id & name fields for testing) is:

After creating, persisting and flushing a new instance, the timetamps are automatically set. After selecting the previous row, changing the name and flushing, the updated timestamp also gets automatically set. After selecting the previous row and deleting it, a deleted timestamp get automatically set.

Please note, the deleted timestamp assumes your database is retaining the data in a “deleted” state, using triggers or other such database functionality to handle Doctrine’s instruction to delete the row. If you are not using this, either ignore the code or remove it.

Advertisements

Simpler Doctrine classes by convention

Doctrine convention adherence leads to simpler entity classes, no picky join column specification. A standard bi-directional one-to-many join becomes simply:

The “One” Entity:

The “Many” Entity:

Nice and straight forward.

The getters & setters can be auto-generated with the following console commands:

$ php app/console doctrine:generate:entities AppBundle:Product

and

$ php app/console doctrine:generate:entities AppBundle:Feature

If desired, now is the time to add any Doctrine Events such as LifeCycle Callbacks, which we do manually until they get better integrated into Doctrine’s console generator commands.

After everything is added, it can be a good style convention to leave a few lines between the field declarations and member functions (including the constructor) as these are just boring plumbing, the field declarations should be the focus.

Switching databases in Symfony upon application events

We’re big fans of the PHP Symfony2 framework and Doctrine2 ORM but a recent project involved a REST API for a multi-client system where each client wanted their database fully separated from each other, but we only knew which client database to connect to once a user had logged in (so no easy config.yml and parameters.yml configuration).

The login gets handled via Java Web Tokens using the excellent Lexik JWT Authentication bundle. So the first call to /auth/login_check with a username and password retrieves a token along with a id of the client (added using the onAuthenticationSuccessResponse listener documented here. Subsequent requests supply a HTTP Authorization header with the token and a custom “client” header specifying the id of the client (also documented in the above link).

This gave us stateless authentication for our API, but we still had to actually switch the Doctrine dbal connection to point to the right database. The solution (inspired by this Stack Overflow question) involved an onKernelRequest() event listener to switch the database from a base database (holds login / authentication data and is referenced in the default connection settings – or whichever connection you’re overriding – of your config.yml file) to the desired database and update the tokenStorage object accordingly. As a tip though, it’s best to keep the base and individual databases schematically identical as possible for reasons explained later.

First create the Event Listener:

Then add this to the services.yml file:

Then add the client databases to the end of the parameters-dist.yml file:

The security.yml file looks something like:

Conclusion:
This solution works fairly well in providing multi-database connectivity based on a site event (in this case user login) with the occasional bit of peering underneath’s Symfony’s hood. As mentioned above, keeping the base database schematically identical (i.e. same table structure, differing data) to your individual databases is very highly advisable. Some Symfony logic occurs before the onKernalRequest event gets fired (looking at your forms) so functionality limitations can otherwise occur there. Also parsers like the Nelmio Api Documentation bundle typically build pre-authentication (so whilst the base database is still selected).

Doctrine Migrations can also be enabled with a little tinkering (I may write a new post on how to do this if there is demand) but again, it helps if the schemas are identical (although isn’t vital).

Doctrine createQueryBuilder() – EntityManager vs. EntityRepository

EntityRepository and EntityManager have slightly different versions of the createQueryBuilder() function. Whereas the EntityManager’s version takes no arguments, EntityRepository’s version expects an ‘$alias‘ parameter. What is going on?!

The EntityRepository class wraps the EntityManager’s call, as such:

From /lib/Doctrine/ORM/EntityRepository.php

The function’s phpdoc reveals the reasoning behind the parameter count differences, EntityRepository returns a version of createQueryBuilder() customised for itself. We no longer need to specify the primary table we’re selecting from. Instead we must supply an $alias parameter which would usually be later supplied to the from() function.

Also note the above means all columns are selected from the entity by default.

Fun with counting in PHP

PHP’s loose typing can throw up some amusing bugs, take using scalars with the count() function. The function isn’t designed for scalars sure, but it doesn’t complain about them and often PHP makes use of global functions like count() rather than the more object orientated $i.count style, creating a nasty little minefield (one of many) for those unfamiliar with PHP’s peculiarities regarding proper objects vs. native types.

So the following looks valid enough:

$i = 5;
if (count($i) > 0) print "true";

But the code is bugged and whilst true will be printed as expected (maybe satisfying the programmer’s initial testing), guess what happens here:

$i = 0;
if (count($i) > 0) print "true";

We get an output of true !?#!??

What happens is the count() function evaluates one scalar value (the 0 integer) and so returns an integer of 1, which is greater than 0.

The following will print true:

$i = false;
if (count($i) > 0) print "true";

Whilst the following will not print anything:

$i = null;
if (count($i) > 0) print "true";

So remember, unless you want weirdness, only use the count() with arrays and objects implementing a Countable interface.

Symfony2 custom exceptions

When using the Symfony2 Framework it is often better to create custom exceptions to handle unique circumstances rather than incorrectly utilising one of the many pre-existing Symfony exception types. Using an interface improves code cohesion, allows the adding of custom functionality as needed and is super easy to setup.

The first step is to create a custom exception interface.

namespace AppBundle\Exception;

interface AppBundleExceptionInterface
{
}

Then create a custom exception class (perhaps in an Exception directory if it suits your project’s structure):

namespace AppBundle\Exception;

class NewTypeOfException extends \Exception implements AppBundleExceptionInterface
{
}

This exception can now be thrown and caught as desired, just be sure to name your exceptions well. You may be throwing them long after they were originally created!

The many different syntaxes of PHP’s if statement

The PHP language is blessed with many possible syntax structures for all sorts of language constructs. Some better than others but all have their place . Here we will be examining flexible usage of some of the styles available for use with if statements.

First, let’s look at the styles for the following statement in the standard c style:

$value = 1;
if ($value == 1) {
    print "if expression run";
} elseif ($value == 2) {
    print "elseif (1st) expression run";
} elseif ($value == 3) {
    print "elseif (2nd) expression run";
} else {
    print "else expression run";
}

(note: elseif has identical else if snytax in above and below examples)

In semi-colon syntax:

$value = 1;
if ($value == 1):
    print "if expression run";
elseif ($value == 2):
    print "elseif (1st) expression run";
elseif ($value == 3):
    print "elseif (2nd) expression run";
else:
    print "else expression run";
endif;

In switch statement format:

$value = 1;
switch (true) {
    case ($value == 1):
        print "if expression run";
        break;
    case ($value == 2):
        print "elseif (1st) expression run";
        break;
    case ($value == 3):
        print "elseif (2nd) expression run";
        break;
    default:
        print "else expression run";
};

The following are recursive language constructs.
In inline recursive format:

$value = 1;
($value == 1?
    (
        print "if expression run"
     ) :
    ($value == 2?
        (
            print "elseif (1st) expression run"
        ) :
        ($value == 3?
            (
                print "elseif (2nd) expression run"
            ):
            (
                print "else expression run"
            )
        )
    )
);

Using logical operators:

$value = 1;
$value == 1 and (print "if expression run")
or $value == 2 and (print "elseif expression run")
or $value == 3 and (print "elseif expression run")
or (print "else expression run");

 

Any other syntaxes missed?

Doctrine DateTime format() errors

A pesky and difficult to debug doctrine problem I’ve been encountering is the following occurring after a flush() call:

PHP Fatal error:  Call to a member function format() on a non-object in /var/www/myapp/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php on line 53

Obviously this gives no info on the actual cause of the error, which it turns out is because of a mismatch between doctrine expecting a DateTime object and instead encountering a string object, which does not have a format() function to call.

The solution is to remove the default string value that doctrine’s orm tools sometimes wrongly attaches to objects and instead use the correct DateTime() object, e.g.:

/**
 * MyObject
 *
 * @ORM\Table(name="my_object_table")
 * @ORM\Entity
 */
class MyObject
{
...
    protected $timestamp = '0000-00-00 00:00:00';
...
}

The first problem if you have a lot of model files is actually finding where the problem is. Whilst there are a host of debug tools which can help, a quick and easy hack is to simply add a stacktrace to the offending doctrine vendor file.

First go to your project’s main folder and vim the relevant file, if you are not a vim file, the substitute it for another one of the many text editors out there:

vim vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php

Then go to line 53 (or whatever line number appears in the error message) by typing :53 (i.e. a semi-colon followed by the line number) where you should see a line reading:

        return ($value !== null)
            ? $value->format($platform->getDateTimeFormatString()) : null;

Go up one line above this and press the a key to enter insert mode and enter:

        if(is_string($value)) {
                debug_print_backtrace();
        }

A good tip is to save the file using :w, but don’t actually close the file. Running your application again you will then print out the usual – hideously ugly – stacktrace. This can be filtered down but even just loooking at the raw ouput should reveal the reflection classes inspecting the model file a couple of steps down which has the incorrectly set line exampled above. This is where you then remove the changes from the above file, by pressing u to undo the changes. Followed by :q to quit the file.

This string needs to be changed to a DateTime() object and you will need to set a default value in the constructor, e.g.:

public function __construct()
    {
        $this->timestamp = new \DateTime();
    }

Leaving out the parameter will be set it to the current system time. This will lead to doctrine correctly interpreting and saving timestamps to the database upon flush.

A more complete strategy to automating timestamp & date generation for data using Doctrine is present in my article:

Automating timestamps with Doctrine ORM

libssh2 vs phpseclib

As tempting as it can be to make use of the simple include library which is phpseclib, it is better (if possible) to install the libssh2 module. Libssh2 it grants PHP access to your system’s OpenSSL implementation rather than relying on phpseclib’s own version which is reason alone to use libssh2 despite phpseclib being undeniably more portable, faster and offering enhanced debug facilities (there’s nothing to stop you switching to phpseclib purely to debug pesky issues or writing code first in phpseclib then porting to libssh2).

Whilst OpenSSL has come under attack recently with exploits such as Heartbleed, it remains one of the best tested and trusted security suites around. Major exploit discoveries like Heartbleed and Shellshock (with its openSSH attack vector) demonstrate the need for systems to be patched as soon as possible.

By using libssh2, any patch to the system’s OpenSSL implementation will be automatically applied to your PHP applications. On a related note, unattended-upgrades / yum-cron should always be enabled to ensure you are patched against exploits as they are released with a seemingly increasing regularity.

On a Ubuntu / Debian libssh2 can be installed via the command:

sudo apt-get install libssh2-php

On Red Hat based systems, use:

yum install libssh2

You then need to add the module to your php.ini file with the following line (place it after all the other extension loading calls):

extension=ssh2.so

Then finally restart apache.

Doctrine not autoloading classes even when they exist

Using doctrine with silex is a great way to combine the power of a good ORM with the efficiency of a micro-framework, however doctrine – well-known for its step learning curve – can be even more frustrating for new users when used outside of the big well-integrated frameworks (e.g. Symfony & Zend.

One problem in particular can be with autoloading. First namespaces need to be taken care of, with a matching directory structure. The doctrine documentation helps with this.

An error which can be particularly troublesome is:

{"statusCode":500,"message":"Class 'SomeClass' does not exist"}

Even after creating the class and placing it in the correct place.

If you using composer, you may simply need to run “composer update” from the command line (wherever the project’s composer.json file is located) to reload the autoloading classes. Until this is done doctrine just won’t be able to see the file and will keep on complaining that it does not exist, even though it does.

Also, remember autoloading is case-sensitive so make sure you have this correct and that there aren’t old copies of wrongly cased files in the same directory.