Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Customising the CMS /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

Different tables for DataObjects with identical structure


Go to End


4 Posts   1867 Views

Avatar
Vromepiet

Community Member, 11 Posts

17 July 2010 at 8:30am

Edited: 17/07/2010 8:31am

Hello,

I'm trying to create some setup tables for a testproject. Those all have the structure:

class Code extends DataObject {
 
   static $db = array(
      'Number' => 'Int',
      'Description' => 'Varchar(100)',
      'Notes' => 'Text',
   );
   
   static $indexes = array(
      array( 'type' => 'unique', 'value' => 'Number' )
   );
 
}

For example, I would like to have Orderstatus (numbers 10 and 20) and InvoiceStatus (numbers 10 and 20), but with a different meaning, so that I can give Orders a has_one Orderstatus and Invoice a has_one InvoiceStatus. Ideally, I would also like to have these records translatable, but that's another issue.

However, when I create this Code class and the OrderStatus and InvoiceStatus (both extending Code), only the code table is created. Probably because the others don't have a $db of their own.

How can I force those other tables to be created? Or should I use a totally different approach?

Thanks,

Jeroen.

Avatar
dhensby

Community Member, 253 Posts

17 July 2010 at 8:49am

Edited: 17/07/2010 8:50am

I think you are taking exactly the right approach.

Why are you worrying about whether SS is creating separate tables? The point of a framework is so that it does that for you, as long as when you fetch a data object it comes back properly, then you don't need to worry.

SS won't create a table for a new extension of a class if it doesn't have any separate/new fields. All that happens is it creates a new allowed classname in the table you are extending.

You don't need to worry about anything, it's looking pretty good where I'm sitting. Keep it up

Avatar
Vromepiet

Community Member, 11 Posts

18 July 2010 at 12:29am

Thanks for your answer.

I think that I do need separate tables or something like it. For example, I would like to be able to have InvoiceStatus 20 and OrderStatus 20, but within the same context (e.g. OrderStatus) it should only be possible to have one record with number 20.

When I force the table to have a unique index on the number column, I would not be able to use 20 as a number on both Invoice and Order. That's why I would like to have 2 tables, to be sure a number cannot be used twice within the entity it is related to. Probable I should put an index on number and the classname column, but is that possible?

Another option would be to define the status simply as an Enum, but that does not give me enough information. Enum is just Enum.
And a little pity is that I cannot use SQL (I think) to fetch e.g. all Orders with status 20 or up, can I?

FYI: The full code I was using (only one subclass as an example)

class Code extends DataObject {
 
   static $db = array(
      'Number' => 'Int',
      'Description' => 'Varchar(100)',
      'Notes' => 'Text',
   );
   
   static $indexes = array(
      array( 'type' => 'unique', 'value' => 'Number' )
   );
   
   public function getCMSValidator() { 
      return new Code_Validator(); 
   }
 
}

class Code_Validator extends RequiredFields { 

   protected $customRequired = array('Number','Description'); 
   protected $entity = "Code";

   /** 
    * Constructor 
    */ 
   public function __construct() { 
      $required = func_get_args(); 
      if(isset($required[0]) && is_array($required[0])) { 
         $required = $required[0]; 
      } 
      $required = array_merge($required, $this->customRequired); 

      parent::__construct($required); 
   } 
    
   function php($data) { 
      $valid = parent::php($data); 
      $number_SQL = Convert::raw2sql($data['Number']); 

      $codes = DataObject::get($this->entity, "`Number` = '{$number_SQL}'");
      if($codes !== null && ((int)$codes->First()->ID != (int)$data['ID'])){
         $this->validationError("Number", sprintf( "Sorry, a record with number %d already exists.", $data['Number'])); 
         $valid = false; 
      } 
       
      return false; 
   } 
}

and OrderStatus

<?php

class OrderStatus extends Code {
   
   public function getCMSValidator() { 
      return new OrderStatus_Validator(); 
   }
 
}

class OrderStatus_Validator extends Code_Validator { 
 
   protected $entity = "OrderStatus";

}

Avatar
Vromepiet

Community Member, 11 Posts

18 July 2010 at 2:54am

A think I have a working solution, see code below. It has a unique index on Number and ClassName, so no duplicates are possible within a group. Also, I've improved the code, so any subclass works without any code in it.

Suggestions are welcome if you find a possible error, I've only just began trying to modify the CMS :-)

<?php

class Code extends DataObject {
 
   static $db = array(
      'Number' => 'Int',
      'Description' => 'Varchar(100)',
      'Notes' => 'Text',
   );
   
   static $indexes = array(
      array( 'type' => 'unique', 'value' => 'ClassName,Number' )
   );
   
   public function getCMSValidator() { 
      return new Code_Validator( get_class($this) ); 
   }
 
}

class Code_Validator extends RequiredFields { 

   protected $customRequired = array('Number','Description'); 
   protected $entity = "Code";

   /** 
    * Constructor 
    */ 
   public function __construct( $entity ) { 
      $required = func_get_args(); 
      if(isset($required[0]) && is_array($required[0])) { 
         $required = $required[0]; 
      } 
      $required = array_merge($required, $this->customRequired);

      $this->entity = $entity;

      parent::__construct($required);
   } 
    
   function php($data) { 
      $valid = parent::php($data); 
      $number_SQL = Convert::raw2sql($data['Number']); 

      $codes = DataObject::get($this->entity, "`Number` = '{$number_SQL}' AND `ClassName` = '{$this->entity}'");
      if($codes !== null && ((int)$codes->First()->ID != (int)$data['ID'])){
         $this->validationError("Number", sprintf( "Sorry, a record with number %d already exists.", $data['Number'])); 
         $valid = false; 
      } 
       
      return false; 
   } 
}

And e.g. ProjectStatus

class ProjectStatus extends Code {

}