Jump to:

5540 Posts in 1738 Topics by 1224 members

Customising the CMS

SilverStripe Forums » Customising the CMS » Different tables for DataObjects with identical structure

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

Page: 1
Go to End
Author Topic: 1191 Views
  • Vromepiet
    Avatar
    Community Member
    11 Posts

    Different tables for DataObjects with identical structure Link to this post

    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.

  • Pigeon
    Avatar
    Community Member
    243 Posts

    Re: Different tables for DataObjects with identical structure Link to this post

    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

  • Vromepiet
    Avatar
    Community Member
    11 Posts

    Re: Different tables for DataObjects with identical structure Link to this post

    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";

    }

  • Vromepiet
    Avatar
    Community Member
    11 Posts

    Re: Different tables for DataObjects with identical structure Link to this post

    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 {

    }

    1191 Views
Page: 1
Go to Top

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.