 eck.classes.inc | 256 +++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 161 insertions(+), 95 deletions(-)

diff --git a/eck.classes.inc b/eck.classes.inc
index fb1a069..b31cf14 100644
--- a/eck.classes.inc
+++ b/eck.classes.inc
@@ -5,30 +5,38 @@ class DBObject implements Iterator{
   public $is_new;
   //Iterator variable
   private $position;
-  
+
   //The database table where the objects exist
-  private $table;
+  private static $table;
   private $vars;
   private $data;
-  
+
   private $primary_keys;
   private $serialize;
-  
-  protected function __construct($table){
+
+  /**
+   * The name of the database field that holds the name of the object.
+   *
+   * @var string
+   */
+  protected static $nameField = 'name';
+
+  protected function __construct(){
+    $table = self::table();
+
     $this->serialize = array();
     $this->is_new = TRUE;
     //Iterator variable
     $this->position = 0;
-    
+
     $data = array();
     //is this a real table, check it
- 
-    
+
+
     if($schema = drupal_get_schema($table)){
-      $this->table = $table;
       $this->primary_keys = $schema["primary key"];
       $this->vars = array_keys($schema['fields']);
-      
+
       //do we want to handle searialized variables by default? let's do it
       //and wait for some critizism
       foreach($schema['fields'] as $name => $field){
@@ -45,21 +53,21 @@ class DBObject implements Iterator{
       //@todo throw an exception
     }
   }
-  
+
   function __set($var, $value){
     if(in_array($var, $this->vars)){
       $this->data[$var] = $value;
     }
   }
-  
+
   function __get($var){
     if(property_exists($this, $var)){
       return $this->{$var};
     }
-    
+
     return $this->data[$var];
   }
-  
+
   public function __isset($name) {
     return isset($this->data[$name]);
   }
@@ -68,72 +76,93 @@ class DBObject implements Iterator{
   public function __unset($name) {
     unset($this->data[$name]);
   }
-  
+
   //DB Interaction Functions
   public function save(){
-    
+
     //before we save, lets serialize the properties that require it
     foreach($this->serialize as $property){
-   
+
       $this->{$property} = drupal_json_encode($this->{$property});
     }
-    
-   
-    
+
+
+
     if($this->is_new){
       $this->id =
-      db_insert($this->table)
+      db_insert(self::table())
       ->fields($this->data)
       ->execute();
     }else{
       //well I need to know what the primary id is to set up the condition;
       $primary_key = $this->primary_keys[0];
-      db_update($this->table)
+      db_update(self::table())
       ->condition($primary_key, $this->{$primary_key}, '=')
       ->fields($this->data)
       ->execute();
     }
-    
+
     //now that we are done saving lets deserialize in case that for some
     //reason we will continue manipulating the properties
     foreach($this->serialize as $property){
       $this->{$property} = drupal_json_decode($this->{$property});
     }
-    
+
     $this->is_new = FALSE;
+    // Clear the table's static caches.
+    drupal_static_reset(__CLASS__ . '::load:' . self::table());
+    drupal_static_reset(__CLASS__ . '::loadAll:' . self::table());
   }
-  
-  protected function load($property, $value){
-    $result = 
-    db_select($this->table, 't')
-    ->fields('t')
-    ->condition($property, $value,'=')
-    ->execute()
-    ->fetchAssoc();
-    
-    if($result){
-      foreach($result as $property => $value){
-        if(in_array($property, $this->serialize)){
+
+  protected function load($property, $property_value){
+    $results = &drupal_static(__CLASS__ . '::' . __FUNCTION__ . ':' . self::table());
+    if (!isset($results[$property][$property_value])) {
+      $results[$property][$property_value] =
+      db_select(self::table(), 't')
+      ->fields('t')
+      ->condition($property, $property_value,'=')
+      ->execute()
+      ->fetchAssoc();
+    }
+
+    if($results[$property][$property_value]){
+      foreach($results[$property][$property_value] as $key => $value){
+        if(in_array($key, $this->serialize)){
           $value = drupal_json_decode($value);
         }
-        $this->{$property} = $value;
+        $this->{$key} = $value;
       }
       //we should only set the is_new flag as false if we loaded something
       $this->is_new = FALSE;
     }
-    
+
+    return $results[$property][$property_value];
   }
-  
+
+  public static function loadAll() {
+    $results = &drupal_static(__CLASS__ . '::' . __FUNCTION__ . ':' . self::table());
+    if (!isset($results)) {
+      $results = db_select(self::table(), 't')
+      ->fields('t', array(self::nameField()))
+      ->execute()
+      ->fetchAllAssoc(self::nameField());
+    }
+    return $results;
+  }
+
   public function delete(){
     //we can only deleted if its a loaded object, or if it has been saved
     if(!$this->is_new){
-      $query = db_delete($this->table);
+      $query = db_delete(self::table());
       $primary_key = $this->primary_keys[0];
       $query->condition($primary_key, $this->{$primary_key}, '=');
       $query->execute();
       //Should we delete the data from the object.. not sure.
       //for right now lets just set it back to new
       $this->is_new = TRUE;
+      // Clear the table's static caches.
+      drupal_static_reset(__CLASS__ . '::load:' . self::table());
+      drupal_static_reset(__CLASS__ . '::loadAll:' . self::table());
     }
     
   }
@@ -162,34 +191,69 @@ class DBObject implements Iterator{
       return FALSE;
     }
   }
+
+  /**
+   * Returns the name of the database table of the class.
+   *
+   * @todo Remove this in PHP 5.3 in favor of directly using late static
+   *   binding.
+   *
+   * @return string
+   *   The name of the database table of the class.
+   */
+  public static function table() {
+    $class = get_called_class();
+    return $class::$table;
+  }
+
+  /**
+   * Returns the name of the database field that holds the name of the object.
+   *
+   * @todo Remove this in PHP 5.3 in favor of directly using late static
+   *   binding.
+   *
+   * @return string
+   *   The name of the database field that holds the name of the object.
+   */
+  public static function nameField() {
+    $class = get_called_class();
+    return $class::$nameField;
+  }
 }
 
 class EntityType extends DBObject{
-  
+
+  /**
+   * The database table of this class.
+   *
+   * @var string
+   */
+  public static $table = 'eck_entity_type';
+
   //If an entity type is new, we can create its table from the current data of
   //the object, but if this is a loaded object, we need to actually keep
   //track of the changes happening so we can modify the already existing table
   //appropiately.
   private $changes;
-  
+
   public function __construct(){
-    parent::__construct('eck_entity_type');
+    parent::__construct();
     $this->properties = array();
     $this->changes = array();
   }
-  
+
   public function addProperty($name, $label, $type, $behavior = NULL){
     if(!$this->is_new){
       $this->recordFieldChange('add', $name);
     }
-    
+
     $p = $this->properties;
     //@todo check that type is an actual type
     $p[$name] = array('label' => $label, 'type' => $type, 'behavior' => $behavior);
-    
+
     $this->properties = $p;
   }
-  
+
   public function removeProperty($name){
     $p = $this->properties;
     if(array_key_exists($name, $p)){
@@ -200,7 +264,7 @@ class EntityType extends DBObject{
       }
     }
   }
-  
+
   public function changeBehavior($name, $behavior){
     $p = $this->properties;
     //@todo check that type is an actual type
@@ -212,14 +276,14 @@ class EntityType extends DBObject{
     }else{
       //@Todo add exception.. the property does not exist
     }
-    
+
     $this->properties = $p;
   }
-  
+
   public function removeBehavior($name){
     $this->changeBehavior($name, NULL);
   }
-  
+
   private function recordFieldChange($op, $name){
     //If it is not new we need to keep track of stuff
     if(!$this->is_new){
@@ -232,16 +296,16 @@ class EntityType extends DBObject{
             $c[$op][] = $name;
           }
         break;
-        
+
         case 'remove':
           //if there is an add in the changes take it out, otherwise add a
           //remove
           if(array_key_exists('add', $c)){
-            
+
             $key = array_search($name, $c['add']);
             if($key != FALSE){
               unset($c['add'][$key]);
-            }     
+            }
           }else{
             $c[$op][] = $name;
           }
@@ -256,19 +320,19 @@ class EntityType extends DBObject{
       module_load_include('inc', 'eck', 'eck.entity_type');
       $schema = eck__entity_type__schema($this);
       db_create_table("eck_{$this->name}", $schema);
-      
+
     }else{
       //modify the already existing table in accordance with the recorded changes
       if(array_key_exists('add', $this->changes)){
         foreach($this->changes['add'] as $name){
-          //first lets get the record 
+          //first lets get the record
           $properties = $this->properties;
           $property = $properties[$name];
           //now we check to see whether it is a default or a custom property
           //it is not custom so lets get the schema and add the field
           $schema = eck_property_type_schema($property['type']);
           db_add_field("eck_{$this->name}", $name, $schema);
-          
+
         }
       }
       if(array_key_exists('remove', $this->changes)){
@@ -277,30 +341,26 @@ class EntityType extends DBObject{
         }
       }
     }
-    
+
     parent::save();
     drupal_get_schema(NULL, TRUE);
   }
-  
+
   public function delete(){
     parent::delete();
     db_drop_table('eck_'.$this->name);
     drupal_flush_all_caches();
   }
-  
+
   public static function loadByName($name){
     $self = new EntityType();
     $self->load('name', $name);
     return $self;
   }
-  
+
   public static function loadAll(){
-    $results = db_select('eck_entity_type', 't')
-    ->fields('t', array('name'))
-    ->execute();
-    
+    $results = parent::loadAll();
     $entity_types = array();
-    
     foreach($results as $result){
       $name = $result->name;
       $entity_types[] = EntityType::loadByName($name);
@@ -310,16 +370,30 @@ class EntityType extends DBObject{
 }
 
 class Bundle extends DBObject{
-  
+
+  /**
+   * The database table of this class.
+   *
+   * @var string
+   */
+  public static $table = 'eck_bundle';
+
+  /**
+   * Overrides DBObject::nameField.
+   *
+   * @var string
+   */
+  protected static $nameField = 'machine_name';
+
   public function __construct(){
     parent::__construct('eck_bundle');
     $this->config = array();
   }
-  
+
   private function createMachineName(){
     $this->machine_name = "{$this->entity_type}_{$this->name}";
   }
-  
+
   private function createLabel(){
     $name = $this->name;
     $pieces = explode("_", $name);
@@ -327,22 +401,22 @@ class Bundle extends DBObject{
     foreach($pieces as $piece){
       $final[] = ucfirst($piece);
     }
-    
+
     $this->label = implode(" ", $final);
   }
-  
+
   public function save(){
     //Lets do some checks before the bundle is saved
     if(isset($this->entity_type) && isset($this->name)){
-     
+
       $save = TRUE;
       //we are good
       //@todo we should check that the entity type is a proper
       //entity type object
-      
+
       //Lets set the machine name
       $this->createMachineName();
-      
+
       //if this bundle is_new we need to check that it does not exist
       //@todo we just need to change the field in the db to be unique
       if($this->is_new){
@@ -351,24 +425,24 @@ class Bundle extends DBObject{
           $save = FALSE;
         }
       }
-      
+
       if(!isset($this->label)){
         $this->createLabel();
       }
-      
+
       if($save){
         parent::save();
       }else{
         //@todo throw some error
       }
-      
+
     }else{
       //if the name an entity type are not set, we can not save
       //the bundle
       //@todo throw soem error or exception
     }
   }
-  
+
   /**
    * This method returns a bundle object
    * @param $machine_name
@@ -382,32 +456,24 @@ class Bundle extends DBObject{
   }
   
   public static function loadAll(){
-    //@todo move this to a general function
-    $results = db_select('eck_bundle', 't')
-    ->fields('t', array('machine_name'))
-    ->execute();
-    
+    $results = parent::loadAll();
     $bundles = array();
-    
+
     foreach($results as $result){
       $name = $result->machine_name;
       $bundles[] = Bundle::loadByMachineName($name);
     }
     return $bundles;
   }
-  
+
   public static function loadByEntityType($entity_type){
-    //@todo move this to a general function
-    $results = db_select('eck_bundle', 't')
-    ->fields('t', array('name'))
-    ->condition('entity_type', $entity_type->name, '=')
-    ->execute();
-    
+    $self = new Bundle();
+    $results = $self->load('entity_type', $entity_type->name);
+
     $bundles = array();
-    
     foreach($results as $result){
       $name = $result->name;
-   
+
       $bundles[] = Bundle::loadByMachineName("{$entity_type->name}_{$name}");
     }
     return $bundles;
@@ -419,7 +485,7 @@ class Bundle extends DBObject{
   *
   * @param $field_type
   *   The type of field to add. One of the keys as defined by any field module using hook_field_info.
-  * 
+  *
   * @param $options
   *   This is an optional array. Its properties can include:
   *   - use existing: If TRUE and if a 'field_name' property is specified in the 'field'
@@ -435,7 +501,7 @@ class Bundle extends DBObject{
   *   - instance: all options accepted by field_create_instance(). Defaults will be used for
   *     each property that is omitted. 'bundle' and 'entity_type' properties are ignored because
   *     they come from the bundle info. The field_name property is either generated or taken from
-  *     the field properties. 
+  *     the field properties.
   *
   * @return
   *   The $instance array with the id property filled in as returned by field_create_instance().
