[limb-svn] r5529 - in 3.x/trunk/limb/active_record: src tests/cases

svn at limb-project.com svn at limb-project.com
Thu Apr 5 12:24:21 MSD 2007


Author: pachanga
Date: 2007-04-05 12:24:21 +0400 (Thu, 05 Apr 2007)
New Revision: 5529
URL: http://fisheye.limb-project.com/changelog/limb/?cs=5529

Modified:
   3.x/trunk/limb/active_record/src/lmbARRecordSetDecorator.class.php
   3.x/trunk/limb/active_record/src/lmbARRelationCollection.class.php
   3.x/trunk/limb/active_record/src/lmbActiveRecord.class.php
   3.x/trunk/limb/active_record/tests/cases/lmbActiveRecordSubclassingTest.class.php
Log:
-- much more robust single table inheritance support - lmbActiveRecord encodes inheritance path in 'kind' field and uses LIKE query in order to retrieve subclasses
-- lmbActiveRecord :: decodeInheritancePath($path) added, it explodes inheritance path and returns an array of classes

Modified: 3.x/trunk/limb/active_record/src/lmbARRecordSetDecorator.class.php
===================================================================
--- 3.x/trunk/limb/active_record/src/lmbARRecordSetDecorator.class.php	2007-04-04 15:08:50 UTC (rev 5528)
+++ 3.x/trunk/limb/active_record/src/lmbARRecordSetDecorator.class.php	2007-04-05 08:24:21 UTC (rev 5529)
@@ -48,8 +48,9 @@
 
   protected function _createObject($record)
   {
-    if($class = $record->get(lmbActiveRecord :: getInheritanceField()))
+    if($path = $record->get(lmbActiveRecord :: getInheritanceField()))
     {
+      $class = end(lmbActiveRecord :: decodeInheritancePath($path));
       if(!class_exists($class))
         throw new lmbException("Class '$class' not found");
       return new $class;

Modified: 3.x/trunk/limb/active_record/src/lmbARRelationCollection.class.php
===================================================================
--- 3.x/trunk/limb/active_record/src/lmbARRelationCollection.class.php	2007-04-04 15:08:50 UTC (rev 5528)
+++ 3.x/trunk/limb/active_record/src/lmbARRelationCollection.class.php	2007-04-05 08:24:21 UTC (rev 5529)
@@ -78,9 +78,8 @@
 
     $criteria = clone $this->criteria;
 
-    $object->addClassCriteria($criteria);
-
     $sort_params = array();
+    $has_class_criteria = false;
 
     if(is_string($magic_params) || is_object($magic_params))
       $criteria->addAnd($magic_params);
@@ -93,12 +92,16 @@
       {
         $filter_object = new $magic_params['class'];
         $criteria = $filter_object->addClassCriteria($criteria);
+        $has_class_criteria = true;
       }
 
       if(isset($magic_params['sort']))
         $sort_params = $magic_params['sort'];
     }
 
+    if(!$has_class_criteria)
+      $object->addClassCriteria($criteria);
+
     $rs = $this->_createDbRecordSet($criteria);
     $this->_applySortParams($rs, $sort_params);
     $dataset = $object->decorateRecordSet($rs);

Modified: 3.x/trunk/limb/active_record/src/lmbActiveRecord.class.php
===================================================================
--- 3.x/trunk/limb/active_record/src/lmbActiveRecord.class.php	2007-04-04 15:08:50 UTC (rev 5528)
+++ 3.x/trunk/limb/active_record/src/lmbActiveRecord.class.php	2007-04-05 08:24:21 UTC (rev 5529)
@@ -44,10 +44,6 @@
    */
   protected $_db_table;
   /**
-   * @var string name of class which should be considered as a base one in single table inheritance relations
-   */
-  protected $_base_class;
-  /**
    * @var string name of class database table to store instance fields, if not set lmbActiveRecord tries to guess it
    */
   protected $_db_table_name;
@@ -801,7 +797,7 @@
     $fields = $this->export();
 
     if($this->isNew() && $this->_isInheritable())
-      $fields[self :: $_inheritance_field] = get_class($this);
+      $fields[self :: $_inheritance_field] = $this->_getInheritancePath();
 
     foreach($this->_composed_of as $property => $info)
     {
@@ -1186,17 +1182,33 @@
    */
   function addClassCriteria($criteria)
   {
-    if(!$this->_isBaseClass() && $this->_isInheritable())
-      return lmbSQLCriteria :: objectify($criteria)->addAnd(array(self :: $_inheritance_field . ' = ?', get_class($this)));
+    if($this->_isInheritable())
+      return lmbSQLCriteria :: objectify($criteria)->addAnd(array(self :: $_inheritance_field .
+                                                                  ' LIKE "' . $this->_getInheritancePath() . '%"'));
 
     return $criteria;
   }
 
-  protected function _isBaseClass()
+  protected function _getInheritancePath()
   {
-    return ($this->_base_class && get_class($this) == $this->_base_class) ||
-           (get_parent_class($this) == __CLASS__);
+    $class = get_class($this);
+    $path = "$class|";
+    while($class = get_parent_class($class))
+    {
+      if($class == __CLASS__)
+        break;
+      $path = "$class|$path";
+    }
+    return $path;
   }
+
+  static function decodeInheritancePath($path)
+  {
+    $items = explode('|', $path);
+    array_pop($items);//removing last empty item
+    return $items;
+  }
+
   /**
    *  Loads current object with data from database, overwrites any previous data, marks object dirty and unsets new status
    *  @param integer object id

Modified: 3.x/trunk/limb/active_record/tests/cases/lmbActiveRecordSubclassingTest.class.php
===================================================================
--- 3.x/trunk/limb/active_record/tests/cases/lmbActiveRecordSubclassingTest.class.php	2007-04-04 15:08:50 UTC (rev 5528)
+++ 3.x/trunk/limb/active_record/tests/cases/lmbActiveRecordSubclassingTest.class.php	2007-04-05 08:24:21 UTC (rev 5529)
@@ -18,13 +18,8 @@
 }
 
 class FooOneTableTestObject extends TestOneTableTypedObject{}
-class BarOneTableTestObject extends TestOneTableTypedObject{}
+class BarFooOneTableTestObject extends FooOneTableTestObject{}
 
-class BaseOneTableTestObject extends TestOneTableTypedObject
-{
-  protected $_base_class = __CLASS__;
-}
-
 class TypedLectureForTest extends lmbActiveRecord
 {
   protected $_db_table_name = 'lecture_for_typed_test';
@@ -33,15 +28,15 @@
 }
 
 class FooLectureForTest extends TypedLectureForTest{}
-class BarLectureForTest extends TypedLectureForTest{}
+class BarFooLectureForTest extends FooLectureForTest{}
 
 class CourseForTestForTypedLecture extends lmbActiveRecord
 {
   protected $_db_table_name = 'course_for_typed_test';
   protected $_has_many = array('lectures' => array('field' => 'course_id',
                                                    'class' => 'TypedLectureForTest'),
-                               'bar_lectures' => array('field' => 'course_id',
-                                                       'class' => 'BarLectureForTest'));
+                               'foo_lectures' => array('field' => 'course_id',
+                                                       'class' => 'FooLectureForTest'));
 }
 
 class lmbActiveRecordSubclassingTest extends UnitTestCase
@@ -61,9 +56,9 @@
 
   function _dbCleanUp()
   {
-    lmbActiveRecord :: delete('TestOneTableTypedObject');
-    lmbActiveRecord :: delete('CourseForTestForTypedLecture');
-    lmbActiveRecord :: delete('TypedLectureForTest');
+    $this->db->delete('lecture_for_typed_test');
+    $this->db->delete('course_for_typed_test');
+    $this->db->delete('test_one_table_typed_object');
   }
 
   function testCreate()
@@ -73,26 +68,28 @@
     $object1->save();
 
     $object2 = new FooOneTableTestObject($object1->getId());
-    $this->assertEqual($object2->title, $object1->title);
+    $this->assertEqual($object2->getTitle(), $object1->getTitle());
 
-    //parents are supertypes
+    //parents are supertypes..
     $object3 = new TestOneTableTypedObject($object1->getId());
+    $this->assertEqual($object3->getTitle(), $object1->getTitle());
 
     try
     {
-      new BarOneTableTestObject($object1->getId());
+      //..while deeper subclasses are not
+      new BarFooOneTableTestObject($object1->getId());
       $this->assertTrue(false);
     }
     catch(lmbARException $e){}
   }
 
-  function testParentDelete()
+  function testSupertypeDelete()
   {
     $foo = new FooOneTableTestObject();
     $foo->setTitle('Some title');
     $foo->save();
 
-    $bar = new BarOneTableTestObject();
+    $bar = new BarFooOneTableTestObject();
     $bar->setTitle('Another title');
     $bar->save();
 
@@ -101,7 +98,7 @@
     $rs = lmbActiveRecord :: find('FooOneTableTestObject');
     $this->assertEqual($rs->count(), 0);
 
-    $rs = lmbActiveRecord :: find('BarOneTableTestObject');
+    $rs = lmbActiveRecord :: find('BarFooOneTableTestObject');
     $this->assertEqual($rs->count(), 0);
   }
 
@@ -111,68 +108,42 @@
     $foo->setTitle('Some title');
     $foo->save();
 
-    $bar = new BarOneTableTestObject();
+    $bar = new BarFooOneTableTestObject();
     $bar->setTitle('Another title');
     $bar->save();
 
-    lmbActiveRecord :: delete('FooOneTableTestObject');
+    lmbActiveRecord :: delete('BarFooOneTableTestObject');//removing subclass
 
-    $rs = lmbActiveRecord :: find('FooOneTableTestObject');
+    $rs = lmbActiveRecord :: find('BarFooOneTableTestObject');
     $this->assertEqual($rs->count(), 0);
 
-    $rs = lmbActiveRecord :: find('BarOneTableTestObject');
+    $rs = lmbActiveRecord :: find('FooOneTableTestObject');//supertype stays
     $this->assertEqual($rs->count(), 1);
-  }
 
-  function testParentFind()
-  {
-    $object1 = new FooOneTableTestObject();
-    $object1->setTitle('Some title');
-    $object1->save();
+    lmbActiveRecord :: delete('FooOneTableTestObject');//removing supertype
 
-    $object2 = new BarOneTableTestObject();
-    $object2->setTitle('Some other title');
-    $object2->save();
-
-    $rs = lmbActiveRecord :: find('TestOneTableTypedObject');
-    $this->assertEqual($rs->count(), 2);
-    $this->assertIsA($rs->at(0), 'FooOneTableTestObject');
-    $this->assertIsA($rs->at(1), 'BarOneTableTestObject');
+    $rs = lmbActiveRecord :: find('FooOneTableTestObject');
+    $this->assertEqual($rs->count(), 0);
   }
 
-  function testOverrideBaseClass()
+  function testFind()
   {
     $object1 = new FooOneTableTestObject();
     $object1->setTitle('Some title');
     $object1->save();
 
-    $object2 = new BarOneTableTestObject();
+    $object2 = new BarFooOneTableTestObject();
     $object2->setTitle('Some other title');
     $object2->save();
 
-    $rs = lmbActiveRecord :: find('BaseOneTableTestObject');
+    $rs = lmbActiveRecord :: find('FooOneTableTestObject');//supertype
     $this->assertEqual($rs->count(), 2);
     $this->assertIsA($rs->at(0), 'FooOneTableTestObject');
-    $this->assertIsA($rs->at(1), 'BarOneTableTestObject');
-  }
+    $this->assertIsA($rs->at(1), 'BarFooOneTableTestObject');
 
-  function testTypedFind()
-  {
-    $object1 = new FooOneTableTestObject();
-    $object1->setTitle('Some title');
-    $object1->save();
-
-    $object2 = new BarOneTableTestObject();
-    $object2->setTitle('Some other title');
-    $object2->save();
-
-    $rs = lmbActiveRecord :: find('FooOneTableTestObject');
+    $rs = lmbActiveRecord :: find('BarFooOneTableTestObject');//subclass
     $this->assertEqual($rs->count(), 1);
-    $this->assertIsA($rs->at(0), 'FooOneTableTestObject');
-
-    $rs = lmbActiveRecord :: find('BarOneTableTestObject');
-    $this->assertEqual($rs->count(), 1);
-    $this->assertIsA($rs->at(0), 'BarOneTableTestObject');
+    $this->assertIsA($rs->at(0), 'BarFooOneTableTestObject');
   }
 
   function testTypedRelationFind()
@@ -186,7 +157,7 @@
     $lecture1->setCourse($course);
     $lecture1->save();
 
-    $lecture2 = new BarLectureForTest();
+    $lecture2 = new BarFooLectureForTest();
     $lecture2->setTitle('Some other title');
     $lecture2->setCourse($course);
     $lecture2->save();
@@ -196,45 +167,21 @@
 
     $course2 = new CourseForTestForTypedLecture($course->getId());
 
-    $this->assertEqual($course2->getLectures()->count(), 2);
+    $this->assertEqual($course2->getLectures()->count(), 2);//supertype by default
     $this->assertIsA($course2->getLectures()->at(0), 'FooLectureForTest');
-    $this->assertIsA($course2->getLectures()->at(1), 'BarLectureForTest');
+    $this->assertIsA($course2->getLectures()->at(1), 'BarFooLectureForTest');
 
-    $foo_lectures = $course2->getLectures()->find(array('class' => 'FooLectureForTest'));
-    $this->assertEqual($foo_lectures->count(), 1);
-    $this->assertIsA($foo_lectures->at(0), 'FooLectureForTest');
+    //narrowing selection but again its supertype for BarFooLectureForTest
+    $lectures = $course2->getLectures()->find(array('class' => 'FooLectureForTest'));
 
-    $bar_lectures = $course2->getLectures()->find(array('class' => 'BarLectureForTest'));
-    $this->assertEqual($bar_lectures->count(), 1);
-    $this->assertIsA($bar_lectures->at(0), 'BarLectureForTest');
-  }
+    $this->assertEqual($lectures->count(), 2);
+    $this->assertIsA($lectures->at(0), 'FooLectureForTest');
+    $this->assertIsA($lectures->at(1), 'BarFooLectureForTest');
 
-  function testFilterTypedRelation()
-  {
-    $course = new CourseForTestForTypedLecture();
-    $course->setTitle('Source1');
-    $course->save();
-
-    $lecture1 = new FooLectureForTest();
-    $lecture1->setTitle('Some title');
-    $lecture1->setCourse($course);
-    $lecture1->save();
-
-    $lecture2 = new BarLectureForTest();
-    $lecture2->setTitle('Some other title');
-    $lecture2->setCourse($course);
-    $lecture2->save();
-
-    $course->getLectures()->add($lecture1);
-    $course->getBarLectures()->add($lecture2);
-
-    $course2 = new CourseForTestForTypedLecture($course->getId());
-
-    $this->assertEqual($course2->getLectures()->count(), 2);
-    $this->assertEqual($course2->getBarLectures()->count(), 1);
-    $this->assertIsA($course2->getBarLectures()->at(0), 'BarLectureForTest');
-    $this->assertIsA($course2->getLectures()->at(0), 'FooLectureForTest');
-    $this->assertIsA($course2->getLectures()->at(1), 'BarLectureForTest');
+    //narrowing more
+    $lectures = $course2->getLectures()->find(array('class' => 'BarFooLectureForTest'));
+    $this->assertEqual($lectures->count(), 1);
+    $this->assertIsA($lectures->at(0), 'BarFooLectureForTest');
   }
 }
 



More information about the limb-svn mailing list