Home > Perl > DBIx::Class and dynamic roles

DBIx::Class and dynamic roles

The DBIx::Class Cookbook already documents how to dynamically create objects in a particular subclass rather than the table’s base class. This is a very useful approach if you have objects that need to work differently based on certain a certain column in a table. (DBIx::Class::DynamicSubclass also does a lot of the work for you).

But what if you want to make use of Moose roles instead of sub-classes (as we often do when using Modern Perl)? It’s easy! In the schema class for the table, just add:

sub inflate_result {
    my $pkg = shift;

    my $self = $pkg->next::method(@_);

    $self->_apply_role;

    return $self;
}

sub _apply_role {
    my $self = shift;
	
    my $role = $self->get_role_name;
    $self->ensure_class_loaded($role);	
    $role->meta->apply($self);	
}

This overrides inflate_result() in the same way as the example in the DBIx::Class cookbook, except that we apply a role, instead of blessing into a different class. Note, you’ll need to define the get_role_name() method. This returns the name of the role’s package (as a string), which you should derive from the object’s data somehow. For instance, you might check if the object has the column ‘admin’ set to true, and if so apply the ‘Admin’ role.

It can also be useful to insert some rows in other columns when the object is first created. To do this, override the insert method:

sub insert {
    my ( $self, @args ) = @_;
	
    $self->next::method(@args);
	
    $self->_apply_role;
	
    $self->init;
}

The ‘init’ method (you might want to use a better name) is on the role that’s applied, so could be different depending on the special things that that role needs to do. For instance, maybe anything with the ‘Admin’ role needs some extra rows inserted into a related table to keep track of which admin permissions a user has. How this init() method operates can either be derived from the data, or passed in via a custom ResultSet method that creates the object.

Note that as you’re calling methods from the roles in your schema class (and potentially vice verca) you probably want to make careful use of the ‘requires’ keyword in your roles, to ensure all the necessary methods are defined somewhere.

Of course, this example only applies one role, but there’s no reason get_role_name() couldn’t be adapted to return multiple role packages, each of which are applied to the object.

About these ads
Categories: Perl
  1. Andrew
    May 25, 2010 at 10:49 am

    “In the schema class for the table, just add…”

    Hey, shouldn’t that be a Role you can apply? :)

    It would “requires ‘get_role_name’;” of course.

    • Mutant
      May 25, 2010 at 12:16 pm

      Yeah, good point :)

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: