Model Object Classes

The Object-relational Mapping (ORM) tool in the Istarel Workshop Application Framework has a number of switches that affect the way model object classes are constructed. Consider a simple table for categories (used to characterize articles on this blog).

iw=> \d category
                            Table "public.category"
   Column    |         TYPE          |                     Modifiers
-------------+-----------------------+--------------------------------------------
 category_id | integer               | NOT NULL DEFAULT nextval('category_seq')
 name        | character varying(25) | NOT NULL
 public_path | character varying(35) | NOT NULL
Indexes:
    "pkey_category" PRIMARY KEY, btree (category_id)
Referenced by:
    TABLE "article_category" CONSTRAINT "fkey_category"
          FOREIGN KEY (category_id) REFERENCES category(category_id)

Here is the simplest use of the Object-relational Mapping (ORM) tool:

cd ~/Sites/fw/install
/orm_install -n Istarel Workshop -w ~/Sites -a iw -r category
Initializing Application...
Parsing Tables in iw...
  Analyzing category...

Default Object Class

For any table in the underlying database, two default classes are created: one contains the default properties and behavior for an individual instance of that class (representing a row in the table), and one contains metadata relevant to all members of that class.

Listing: /iw/rsrc/model/default/DefaultCategory.php

class DefaultCategory extends ORMObject
{
   // Properties representing table columns
   public $category_id;
   public $name;
   public $public_path;

// Factory

   function factoryClass() { return 'CategoryFactory'; }

// Many Relations

   function articleCategories($requestor)
   {
      $select = new ORMSelect('article_category');
      $select->addCriteria(new ORMCriterion('category_id', $this->category_id));
      $this->restrictQuery($requestor, $select, 'ArticleCategory');
      return ORMFactory::instanceArray('ArticleCategory', $select);
   }

// Validation

   function validateName()
   {
      $error = false;
      if (! $this->applyRule('IWRequiredRule', 'name'))
         $error[] = IWDatabase::ERROR_IS_NULL;
      if (! $this->applyRule('IWLengthRule', 'name', new IWRange(0, 25)))
         $error[] = IWDatabase::ERROR_TOO_LONG;
      if ($error) return $this->errorMessage('name', $error);
   }

   function validatePublicPath()
   {
      $error = false;
      if (! $this->applyRule('IWRequiredRule', 'public_path'))
         $error[] = IWDatabase::ERROR_IS_NULL;
      if (! $this->applyRule('IWLengthRule', 'public_path', new IWRange(0, 35)))
         $error[] = IWDatabase::ERROR_TOO_LONG;
      if ($error) return $this->errorMessage('public_path', $error);
   }
}

Default classes are intended to not be touched by developers. If the database schema changes, the ORM tool can be run again, modifying the default classes. For each default classes, there is a shell subclass created (in this case, Category) intended for use by developers.

Default Factory Class

For each database table, a default factory class is created that provides metadata to aid in the instantiation of individual objects that represent a row in the database table. From an application developer perspective, the factory class is the place to put methods that result in objects (such as an array of objects meeting certain criteria).

Listing: /iw/rsrc/model/default/DefaultCategory.php

class DefaultCategoryFactory extends ORMFactory
{
   function createCategoryFactory()
   {
      return parent::createORMFactory('CategoryFactory');
   }

   function retrieveCategory($property_value = null,
                             $property_name = null,
                             $properties = ORMObject::ALL_PROPERTIES)
   {
      return ORMFactory::retrieveObject('Category', $property_value,
                                                    $property_name,
                                                    $properties);
   }

   function instanceClass() { return 'Category'; }

   function sourceName() { return 'category'; }

   function identifierProperty() { return 'category_id'; }

   function primaryKeySequence() { return 'category_seq'; }

   function propertyType()
   {
      return array(
            'category_id' => ORMPostgreSQLAdapter::PGSQL_INT4,
            'name'        => ORMPostgreSQLAdapter::PGSQL_VARCHAR,
            'public_path' => ORMPostgreSQLAdapter::PGSQL_VARCHAR
      );
   }

   function noCopyProperties() { return array('category_id'); }
}