ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

DataMapper ORM v1.8.2

November 30, 2011 3:43pm

Subscribe [100]
  • #226 / Mar 18, 2012 6:50am

    WanWizard

    4475 posts

    There are several prefixes at play here.

    The first one is the one defined in the CI database definition, and is used application wide, and that includes Datamapper. You use this prefix if you store non-CI-app tables in the same database, and you want to make sure you have no collisions.

    The second one is the one defined in the datamapper config file. It will be applied to all tables accessed by Datamapper through the models. It is mainly handy if your application has a mix of Datamapper and non-Datamapper tables, and you want to separate the two (again, to avoid collisions).

    In this situation you might want to use the per-model prefix to override the second one, usually to set it to “” (empty string), so the model can access the table without Datamapper prefix (for example because it is a table shared with the non-DM part of the application).

    I have never encountered a situation where the per-model prefix was used to set some other prefix. The only use-case I can think of is that you have several Datamapper driven applications using the same database, no CI prefix is defined, and the global Datamapper prefix is used to separate the application tables. You can then use the per-model prefix (for example for a users model) to share tables between applications by setting the prefix for this model the same in all applications.

    I don’t have a problem using some second ‘prefix’ in the table name to group tables within the database. I usually do that in a modular design (I prefix with the module name), again to avoid collisions. For an authentication module, I would indeed have table names starting with ‘auth_’.

    If the CI prefix is then ‘CI_’, the Datamapper prefix ‘DM_’, the table name would be something like ‘CI_DM_auth_users’. I can live with that (it makes it absolutely clear what it is), and I don’t really have a problem with the fact that this would create ‘CI_DM_auth_groups_auth_users’ as relationship table. If you have an issue with this, you can name the relationship table using the ‘join_table’ field if you use advanced relationship definitions.

  • #227 / Mar 18, 2012 7:03am

    WanWizard

    4475 posts

    As to the question about timestamps, just overload the save() method in your model:

    // your model
    public function save($object = '', $related_field = '')
    {
        // check if object has a 'created' field, and it is not already set
        if (in_array($this->created_field, $this->fields) && empty($this->{$this->created_field}))
        {
            $this->{$this->created_field} = 'add your custom data here';
        }
    
        // and call the DM save() method to save the object
        return parent::save($object, $related_field);
    }

    You can do the same with other fields or methods. There are users that have overloaded several methods to implement soft delete functionality, where records are not deleted but marked as deleted.

    If you want to use this for multiple models, create a base model for it:

    class Basemodel extends Datamapper
    {
        // your base model methods here
    }
    
    class User extends Basemodel
    {
       // your normal model info here
    }

    Now your User model will inherit all methods defined in the Basemodel, as well as all methods in the Datamapper class.

  • #228 / Mar 18, 2012 10:20am

    North2Alaska

    58 posts

    As to the question about timestamps, just overload the save() method in your model:

    // your model
    public function save($object = '', $related_field = '')
    {
        // check if object has a 'created' field, and it is not already set
        if (in_array($this->created_field, $this->fields) && empty($this->{$this->created_field}))
        {
            $this->{$this->created_field} = 'add your custom data here';
        }
    
        // and call the DM save() method to save the object
        return parent::save($object, $related_field);
    }

    You can do the same with other fields or methods. There are users that have overloaded several methods to implement soft delete functionality, where records are not deleted but marked as deleted.

    If you want to use this for multiple models, create a base model for it:

    class Basemodel extends Datamapper
    {
        // your base model methods here
    }
    
    class User extends Basemodel
    {
       // your normal model info here
    }

    Now your User model will inherit all methods defined in the Basemodel, as well as all methods in the Datamapper class.

    This is exactly what I was looking for.  Thank you!

  • #229 / Mar 18, 2012 2:14pm

    North2Alaska

    58 posts

    This leads me to feature request.

    In the save function we find

    // Check if object has a 'created' field, and it is not already set
       if (in_array($this->created_field, $this->fields) && empty($this->{$this->created_field}))
       {
        $this->{$this->created_field} = $timestamp;
       }

    I would like the update date also be set

    // Check if object has a 'created' field, and it is not already set
       if (in_array($this->created_field, $this->fields) && empty($this->{$this->created_field}))
       {
        $this->{$this->created_field} = $timestamp;
        $this->{$this->updated_field} = $timestamp;
       }

    What this would do is ensure that the update field would always be set.  Subsequent queries would only have to search the update field for date information rather than having to check both.

  • #230 / Mar 18, 2012 3:15pm

    WanWizard

    4475 posts

    The created field is only set if it wasn’t set before (which is only on a new object).

    The updated field is modified a bit further in the code, when Datamapper detects you have changes one of more values (i.e. retrieving a record and saving it again doesn’t modify the updated_field).

    On new records the updated field isn’t modified, as there haven’t been any updates yet.

  • #231 / Mar 18, 2012 11:26pm

    North2Alaska

    58 posts

    On new records the updated field isn’t modified, as there haven’t been any updates yet.

    This is an ongoing battle in my 30 year career.  Do you consider a new record as updated as well?  Some camps take your position, that nothing has been updated, so no.  Others take the position that it was an empty record before but was updated (by doing the insert) and as such, the update date should be recorded as well.  I’m of this second camp.

    The other justification is when doing a query to get all the records that have changed or created in a given period, it makes the queries simpler because you only have to query the update date.  If it becomes significant when the record was created, (which it usually is not) then you can either compare the two or query the create date directly.

    So, I’m going to use your suggestion above and overload the save function to handle my point of view.  Maybe another config variable is in order.  If you would like I could put together the code…

  • #232 / Mar 19, 2012 3:36am

    WanWizard

    4475 posts

    You can’t please everyone all of the time… 😉

  • #233 / Mar 19, 2012 7:52pm

    North2Alaska

    58 posts

    I’m working on the Contact information of our system.  I have a contacts table and an attributes table.  The idea is the attributes table can hold a phone number, email address, IM account, or dates of some kind.  Rather than a single attributes model, I’m thinking I would like to have a phone model that selects attributes of type phone.

    Is this a reasonable plan or is there a better/more preferred way of doing this?

  • #234 / Mar 19, 2012 8:04pm

    WanWizard

    4475 posts

    If the amounts and type of attributes are variable, that is the only solution. Datamapper doesn’t support EAV implementations.

  • #235 / Mar 19, 2012 8:34pm

    North2Alaska

    58 posts

    I’m working on the Contact information of our system.  I have a contacts table and an attributes table.  The idea is the attributes table can hold a phone number, email address, IM account, or dates of some kind.  Rather than a single attributes model, I’m thinking I would like to have a phone model that selects attributes of type phone.

    Is this a reasonable plan or is there a better/more preferred way of doing this?

    OK, digging deeper into the documentation. I’m reading the advanced relationships section, and I’m getting close, but not there yet.  It’s a little more complicated than I detailed above.  There are three tables involved;  contacts, resources, and attributes.

    Contacts is more than just this but this is all we need for this exercise.
    CREATE TABLE `ab_contacts` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT
    ) ;

    The attributes table is a simple list of type and value.  Type may be phone, email, etc… and value may be work, home, mobile, etc…
    CREATE TABLE `ab_attributes` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `type` varchar(25) DEFAULT NULL,
      `value` varchar(25) DEFAULT NULL
    ) ;

    Now we have a table to join them up called resources.  As I type this I see that I may need to rename the table, but let’s continue for the moment.  Here we have just a value field to store the entered data. 
    CREATE TABLE `ab_resources` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `contact_id` bigint(20) DEFAULT NULL,
      `attribute_id` bigint(20) DEFAULT NULL,
      `value` varchar(255) DEFAULT NULL
    ) ;

    We join the table with the contact_id to the contacts table and attributes table.  This is really a many to many table with an extra field for the value related to the relationship.  I can use the set_join_field function to populate this value.  I’m good so far.

    So, here is where I think the complexity is.  When I query for the resources, I don’t want all the resources, I just want the phone numbers for example.  And there may be specific things that need to happen to the phone number (formatting it).  To me this sounds like a model.  But I don’t see how to create a Phone model where only the resources with a related type of Phone are the results of the model.

    I’m still reading the docs, but in the absence of a lot of testing, I’m not seeing it.  Any pointers?

  • #236 / Mar 19, 2012 9:22pm

    North2Alaska

    58 posts

    Datamapper doesn’t support EAV implementations.

      I’ve not heard that term before.  I’ll study it out…

  • #237 / Mar 20, 2012 5:01am

    WanWizard

    4475 posts

    You can use where_related_attibute(‘type’, ‘value’) to select only a specific type when querying the relation.

    If you need to format the phone number, you can use a set_rule to do that when you retrieve the data from the database. Make sure you have a corresponding rule that will convert the formatted value back to the raw data so when you save it, it doesn’t save the formatted value.

  • #238 / Mar 21, 2012 11:42am

    Mareshal

    230 posts

    I have a table, that is in a relation: one to many with other 4 tables.

    But the following code executes 5 queries. Why not use JOINs ?

    $v = new Video(1);
        $v->video_category;
        $v->video_rating;
        $v->video_flag;
        $v->video_stat;

    LE:

    I’ve reduced it to this

    $v->include_related('video_category')
          ->include_related('video_rating')
          ->include_related('video_flag')
          ->include_related('video_stat')
          ->get_by_id(1);

    But when I am accessing the video_category object, it makes another query

    foreach($v->video_category as $a) echo $a->category_id . "; ";
  • #239 / Mar 21, 2012 4:19pm

    WanWizard

    4475 posts

    In your first example you have 5 different statements in which you request data the current object doesn’t have. How would you implement that using JOIN’s? Make the code physic so it knows at the first statement that you intent to write more?

    The second example shows you Datamapper will use JOIN’s when it has the entire question in a single statement.

    Your third statement is a repeat of the first. There you say “Oh, and I need this too”. How would Datamapper know in the previous statement that you intend to ask for more data later?

  • #240 / Mar 22, 2012 8:13am

    North2Alaska

    58 posts

    @WanWizard

    I would like to add some features to DataMapper.  I’m not sure how to go about it or how/where best to do it.  Here is what I want to add.

    1)  When the columns exist, store the create/update fields in the joining table.
    2)  Config option to store the update field at the same time as the create field.
    3)  Config option to store a create/update user id when the columns exist.

    1)  I’m not sure where to even begin on this one.  The idea is that I want/need to capture when the relationship was established.  For example user and group.  I want to know when the user was added to the group.  This becomes even more important when the joining table has additional data.

    2)  I think I could create a new value in the config file:

    $config['update_on_create'] = FALSE;

    and then in the save function add the code to do the work.

    3)  The idea here is that I would like to know who created/updated the record and I would like to have it automatic if the field exists.  I’ve played around with this and have not been successful.  The config could/should define the variable to be used for this value, the created_user_field, and updated_user_field. I can use the same method to check for the existence of the fields,  I can’t figure out the best way to populate the value to store. 

    I would be glad to do the work, I just need some direction on how/where and if you feel these would be valuable additions.

    Your thoughts?

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases