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]
  • #241 / Mar 22, 2012 11:05am

    WanWizard

    4475 posts

    To start with a general remark: this is not really generic functionality that should belong in Datamapper. It’s specific to your case. Best way to implemented is to create a base model that extends Datamapper, add your specific functionality to it, and have all your models extend this base model instead of Datamapper.

    2) and 3) can be solved by overloading the save() method, 1) can be achieved by overloading the _save_relation() method.

    This way you don’t have to patch the Datamapper library, which will lead to headaches when it’s time to do a version upgrade.

  • #242 / Mar 22, 2012 12:01pm

    North2Alaska

    58 posts

    To start with a general remark: this is not really generic functionality that should belong in Datamapper.

    That was really the heart of the question.  OK, I’ll work on your suggestions.  I’ve already overloaded the Save function and can look into the other. 

    Thanks.

  • #243 / Mar 22, 2012 3:25pm

    animatora

    25 posts

    I am new to DataMapper ORM in CodeIgniter, here is my question. According to the manual :

    Be careful with this method. Without having limited it with where statements or similar methods it will modify every single row on the table!
    
    Also, this method bypasses validation, and can also operate on in-table foreign keys, so please be aware of the risks.

    If the update method bypasses validation, what is the way to update a record validating it before update? A sample code will be appreciated.

  • #244 / Mar 22, 2012 3:35pm

    North2Alaska

    58 posts

    I am new to DataMapper ORM in CodeIgniter, here is my question. According to the manual :

    Be careful with this method. Without having limited it with where statements or similar methods it will modify every single row on the table!
    
    Also, this method bypasses validation, and can also operate on in-table foreign keys, so please be aware of the risks.

    If the update method bypasses validation, what is the way to update a record validating it before update? A sample code will be appreciated.

    I think the best way is to use the Save function.

    $u = new User();
    $u->get_where("id", 1);
    
    $u->first_name = "Bill"
    $u->last_name = "Jones"
    
    $u->Save();
  • #245 / Mar 22, 2012 4:47pm

    WanWizard

    4475 posts

    Correct.

    You don’t use the update() method to update your record, it’s meant for mass updates to your table (it generates an UPDATE query).

    The save() method will determine automatically if an INSERT or UPDATE is needed to save the current object state.

  • #246 / Mar 23, 2012 5:48pm

    North2Alaska

    58 posts

    I’ve already overloaded the Save function and can look into the other.

    Well, I don’t see how to overload a Protected function.  Two problems arrise. 1) The _save_relation uses other protected functions that are not reachable from the overloading Class.  2)  I can’t call parent::_save_relation to have it do normal operations like I did with the Save function.

    I think this functionality has to be internal to DM.  Not sure what else to do.  (Showing my Noobness :-D )

  • #247 / Mar 23, 2012 7:05pm

    rherriman

    19 posts

    I’m having an issue I hope that you can provide some insight on, WanWizard.  For reference, we are currently using DM 1.8.1 on CI 2.0.2—they’ve been a little reluctant to upgrade here at work after those issues introduced in 2.0.3 with protected methods.  But I don’t think this is related to my problem.

    In several of my models now, I’ve taken to extending the __get magic method in certain cases: when simple $object->relation querying doesn’t suffice.  For example, we have “categories” (infinitely deep) and “products” that are assigned to them.  We also have “media” that we can attach to either categories or products.  Now let’s say that I want to get a (distinct) list of media for a particular product, as well as the media assigned to its direct parent category.  $product->media->get() won’t provide that.  Ideally, too, that functionality would be part of the model itself.  My solution was to do this:

    class Product extends DataMapper {
     ...
     public function __get($name) {
      // Prepare the resolved_media property. More than just an alias of
      // media, this will also retrieve the UNION of $product->media and
      // $product->category->media.
      if($name == 'resolved_media') {
       $this->{$name} = new Media();
       
       if(!$this->exists()) {
        // Ensure an empty result set is returned if this product does
        // not exist yet: if it doesn't exist, there are no relations.
        // Yes, I know this is kind of… unpleasant.
        $this->{$name}->where('id', 0);
       } else {
        $this->{$name}->distinct();
        $this->{$name}->group_start();
        $this->{$name}->where_related_product('id', $this->id);
        $this->{$name}->or_where_related('category/product', 'id', $this->id);
        $this->{$name}->group_end();
       }
       
       return $this->{$name};
      }
    
      return parent::__get($name);
     }
     ...
    }

    This works as I had hoped.  You can do $product->resolved_media->{other query methods}->get() and end up with the results you would expect.  However, it only seems to work correctly once.  If you want to run another query on resolved_media, it ignores all of the filtering defined in __get.  It does, however, honor method chaining.  resolved_media itself just becomes something of a blank slate, no different than if you were running queries on a fresh instance of Media.

    This is one of the simpler examples that I have.  Ultimately I’m providing these as short hand for the other developers on my team who are less well versed in writing DataMapper queries.  Plus, it has a nice side benefit of helping to promote consistency in query results across the application.

    I’m sure that I’m missing something completely obvious.  Are you able to see what I’m doing wrong?

    - ryan

    EDIT:
    Naturally, no more than 20 seconds after posting this I realized what was going on.  After the query is run and the results retrieved, the actual “query” itself is wiped clean just like it would be for any DM object.  So I guess, a different question: once get() is called on resolved_media, is there a way for me to restore this “default” query?

  • #248 / Mar 24, 2012 4:45am

    WanWizard

    4475 posts

    @North2Alaska,

    It should not be a problem to overload methods that are defined “protected”. What is the problem you have?

  • #249 / Mar 24, 2012 4:50am

    WanWizard

    4475 posts

    @rherriman,

    Datamapper uses CI’s active record library to construct and run queries. It’s CI’s get() that resets the defined query after execution, which is logical because otherwise the residue would taint the following queries.

    There is no way to retain the query, other then perhaps clone the object before the get.

  • #250 / Mar 24, 2012 6:39am

    North2Alaska

    58 posts

    It should not be a problem to overload methods that are defined “protected”. What is the problem you have?

    In my Basemodel, I overload the Save function, for example.  I need to use the timestamp function to set the updated_field when the created_field is set.  So I want to call _get_generated_timestamp(), but it is a private function.

    public function save($object = '', $related_field = '')
     {
      $timestamp = parent::_get_generated_timestamp();

    When I do this I get an error: PHP Fatal error:  Call to private method DataMapper::_get_generated_timestamp()

    So, what I ended up doing is just copying the function to Base class and changed the call to

    $timestamp = $this->_get_generated_timestamp()

    Obviously, I’m doing something wrong.  I’m reading PHP docs to try and understand overloading, but the answer is still eluding me.

  • #251 / Mar 24, 2012 7:39am

    WanWizard

    4475 posts

    Ah, they are private, not protected. That’s not ok.

    Just go into the Datamapper library, and change all “private function” to “protected function”. Methods should be extendable.

    I’ll correct this at the next update.

  • #252 / Mar 24, 2012 9:57am

    North2Alaska

    58 posts

    Just go into the Datamapper library, and change all “private function” to “protected function”. Methods should be extendable.

    I’ll correct this at the next update.

    That helps.  😊

    When _save_relation is called, I can’t figure out how I determine what table is being saved.  I’ve looked at $this->table, but it returns the original table, not the related table.  How do I check what fields the join table has? How can I determine if it even is a joining table?

    Once again, I kindly ask you to point me in the direction I need to go.

  • #253 / Mar 24, 2012 11:47am

    WanWizard

    4475 posts

    It determines the table name using

    $relationship_table = $this->_get_relationship_table($object, $related_field);

    If it is the same as $this->table, the foreign key of the relation is in the current table. If not, the table name returned can point to another table, or to a relationship table.

  • #254 / Mar 26, 2012 10:44am

    rherriman

    19 posts

    @rherriman,

    Datamapper uses CI’s active record library to construct and run queries. It’s CI’s get() that resets the defined query after execution, which is logical because otherwise the residue would taint the following queries.

    There is no way to retain the query, other then perhaps clone the object before the get.

    Right, I understand that.  I just thought DM must be doing something special, since $product->media will always filter out the Media objects NOT associated with the product without any interference from myself…

  • #255 / Mar 26, 2012 12:36pm

    WanWizard

    4475 posts

    That is the power of an ORM.

    Datamapper knows which records are related, $product->media will only return the subset of related records.

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

ExpressionEngine News!

#eecms, #events, #releases