Clinton Wolfe
and 1 contributors


Class::ReluctantORM::SubClassByRow - ORM base class for behavior inheritance


  package ShipType;
  use base 'Class::ReluctantORM::SubClassByRow';
    schema => 'highseas',
    table => 'ship_types',
    primary_key => 'ship_type_id',
    subclass_column => 'subclass_name',
    subclass_preload => 1,


  package ShipType::Galleon;
  sub set_sail { ... }

  package ShipType::Rowboat;
  sub set_sail { ... }

  package main;
  my $ship = Ship->fetch_deep(with => { ship_type => {} }, where => ...);
  my $st = $ship->ship_type();
  $st->isa('ShipType::Galleon');  # true if the ship_type->subclass_name eq Galleon
  $st->isa('ShipType');           # true
  $st->set_sail();                # polymorphic


CRO usually treats rows as instances, and tables as classes. But what if what you are storing classes in the tables? This base module allows you to treat a table's rows as both classes and instances (an instance of a metaclass, basically). This is most useful for "type tables" in which you want the behavior of an object to vary with its type. In otherwords, this can provide for behavioral inheritance and polymorphism (by implementing methods in your specific subclasses).

TODO - compatible with CRO::Static?


Whenever a ShipType object is fetched from the database, we examine the column named by the subclass_column to determine which subclass it should be (if the value of the column contains colons, it is used as-is; if no colons are present, the base class is prefixed (ie, 'Dread::Naught' => Dread::Naught, 'Galleon' => 'ShipType::Galleon'. That subclass is loaded (if it hasn't been loaded already), we confirm that the subclass ISA ShipType (if not, we push ShipType to the front of its @ISA), an optional class initter is run (postload_init) and then the object is created and blessed as the specified subclass.

SubClassByRow also makes arrangements so that metadata requests on a subclass will be handled by the superclass.



This class method sets up your classes. In addition to the options permitted to Class::ReluctantORM->build_class, you may also use:


Required string. Column to examine when instantiating objects to determine class of new object.


Optional boolean, default false. If true, we'll try to load any modules under the directory where the superclass lives (ie, we'll try to load anything under ShipType/*.pm, ShipType/*/*.pm, etc; anything that then claims to be a ShipType will be registered). If false, class loading will occur on an ad hoc basis as rows are returned and new subclass_column values are seen.

my $thing = YourClass->new(%attributes);

Overrides the default CRO constructor. Acts as a factory method - based on the value of the sublass_column attribute, determines the actual class to bless the object into. Loads the class if neccesary.


Optionally, you can define this method. It will be called the first time the subclass is loaded, but is gaurenteed to be called after the class's metadata is established. Default implementation is a no-op.


Clinton Wolfe