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 1.6.0

September 05, 2008 12:32pm

Subscribe [115]
  • #496 / Feb 10, 2009 12:21am

    Yman

    7 posts

    help! i can’t save relationship
    this is what i’ve done:

    Controller

    $n = new Entry();
            $n->limit(1)->get();
            
            //saving relationship here
            $c1 = new Horizontal();
            $c1->where('name', $this->input->post('horizontal'))->get();
            $n->save($c1);


    Model (Entry)

    class Entry extends DataMapper {
    
        var $has_one = array("horizontal");
        
        var $validation = array(
            array(
                'field' => 'know_fragment',
                'label' => 'Knowledge Fragment',
                'rules' => array('required', 'trim')
            ),
            array(
                'field' => 'severity',
                'label' => 'Severity Level',
                'rules' => array('integer', 'required')
            ),
            array(
                'field' => 'remark',
                'label' => 'Remarks',
                'rules' => array('trim')
            ),
            array(
                'field' => 'solution',
                'label' => 'Solutions',
                'rules' => array('trim')
            ),
            array(
                'field' => 'switch',
                'label' => 'Switch On Off',
                'rules' => array('integer')
            )
        );

    Model (Horizontal)

    class Horizontal extends DataMapper {
    
        var $has_many = array("entry");
        
        var $validation = array(
            array(
                'field' => 'name',
                'label' => 'Name',
                'rules' => array('required', 'trim', 'unique')
            ),
            array(
                'field' => 'entry',
                'label' => 'Entry',
                'rules' => array() 
            )
        );

    when i try saving the relationship, no error shown but yet fail to save.

    Error

    A Database Error Occurred

    Error Number: 1054

    Unknown column ‘entry_id’ in ‘where clause’

    SELECT * FROM (`entries_horizontals`) WHERE `entry_id` = ‘1’ AND `horizontal_id` = ‘2’

  • #497 / Feb 10, 2009 12:30am

    OverZealous

    1030 posts

    Why are you re-getting your Entry in the first section?  You do not ever have to do this.  By doing this, you are re-querying the Entry table, and resetting it to whatever item happens to be first.

    Also, as a shortcut, DM now supports combining the save for relationships and objects, just use this:

    $n = new Entry();
    $n->entry_no = $this->input->post('entry_no');
    $n->know_fragment = $this->input->post('know_fragment');
    $n->severity = $this->input->post('severity');
    $n->remark = $this->input->post('remark');
    $n->solution = $this->input->post('solution');
    $n->onoff = $this->input->post('onoff');
    $c1 = new Horizontal();
    $c1->where('name', $this->input->post('horizontal'));
    $n->save($c1);

    DataMapper automatically sets the ID that the new object was saved as.  If you still want to re-look it up for some reason (such as retrieving default values for other columns), do it like this:

    $n->get_by_id($n->id);
  • #498 / Feb 10, 2009 1:29am

    Yman

    7 posts

    thanks OverZealous,

    i have a question here, is there anyway plugins or something for us to import .csv file and saving relationship simultaneously

  • #499 / Feb 10, 2009 2:02am

    OverZealous

    1030 posts

    No, there is not.  You can write one in PHP without too much trouble.  I wrote one for debugging and testing purposes, but it is fairly specific.  My design was this:

    Name of CSV file was the model.
    First row of CSV has the field or related object names.
    Process the CSV using example code from the php website.
    On the first loop, store the header row so you can figure out the field names.
    Create a new object, save the fields, and save it to the database.

    Here’s something to get you started.  It’s hacked down from my code, so there may be mistakes.

    // set these yourself
    $csv_files = array('model1', 'model2', ...);
    $path = APPPATH . 'import/';
    
    foreach($csv_files as $model) {
        if(! class_exists($model)) {
            $this->_show_error("Error: unable to find class $model");
        }
        $handle = fopen($path . $model . '.csv', 'r');
        ini_set('auto_detect_line_endings', TRUE);
        $row = 0;
        $header;
        while (($data = fgetcsv($handle)) !== FALSE) {
            if($row == 0) {
                // save the header, ...
                $header = $data;
            } else {
                $o = new $model();
                echo "  Saving $model(";
                foreach($data as $index => $d) {
                    if($index > 0) {
                        echo ", ";
                    }
                    echo "\"$d\"";
                }
                echo ") ... ";
                foreach($header as $index => $field) {
                    if($index >= count($data)) {
                        // we've looked up everything, there must be extra header columns
                        break;
                    }
                    $d = $data[$index];
                    // skip empty columns
                    if( $d === '') {
                        continue;
                    }
                    if(in_array($field, $o->fields)) {
                        // save the data
                        $o->{$field} = $d;
                    } else if(in_array($field, $o->has_one)) {
                        // hopefully, all of the $fields were first.  Otherwise this can be wasteful
                        $other_obj = new $field();
                        $other_obj->get_by_id($d);
                        if( ! $other_obj->exists()) {
                            $this->_show_error("Error loading relationship $field($d) on object $model: That id does not exist.");
                        }
                        if( ! $o->save($other_obj) ) {
                            print_r($o->error->string);
                            $this->_show_error("Error saving object $model($id) with one relationship to $field($d).");
                        }
                    } else if(in_array($field, $o->has_many)) {
                        // hopefully, all of the $fields were first.  Otherwise this can be wasteful
                        $other_ids = explode(',',$d);
                        foreach($other_ids as $other_id) {
                            $other_obj = new $field();
                            $other_obj->get_by_id(trim($other_id));
                            if( ! $other_obj->exists()) {
                                $this->_show_error("Error loading relationship $field($other_id) on object $model: That id does not exist.");
                            }
                            if( ! $o->save($other_obj, $field) ) {
                                print_r($o->error->string);
                                $this->_show_error("Error saving object $model($id) with many relationship to $field($other_id).");
                            }
                        }
                    } else {
                        $this->_show_error("Error saving object $model: No field or relationship for $field.  (Data: $d)");
                    }
                }
                if( ! $o->save() ) {
                    print_r($o->error->string);
                    $this->_show_error("Error saving object $model with expected id $id");
                }
                echo "done.\n";
            }
            $row++;
        }
        fclose($handle);
    }
  • #500 / Feb 10, 2009 2:39am

    Yman

    7 posts

    waoh, thanks man!

    let me try it out 1st =D

  • #501 / Feb 10, 2009 2:39pm

    easylancer

    42 posts

    Ok I have some problems with Datamapper, maybe its me not understanding it or maybe its documentation just doesn’t have this scenario. I have a table model called driver and another called car, I want to be able to save a driver to a car at the same time when i’m saving a new car and a new driver. Eg.

    // Car Model
    $c = new Car();
    $c->model = $_POST['model'];
    $c->year = $_POST['year'];
    
    // Driver Model
    $d = new Driver();
    $d->name = $_POST['name'];
    $d->age = $_POST['age'];
    $d->insurance = $_POST['insurance'];
    
    $d->save();
    $c->save();

    How can I save the driver to the car at this point?

  • #502 / Feb 10, 2009 2:45pm

    OverZealous

    1030 posts

    First, I don’t believe you have read the docs, since this is clearly explained, several times.

    Second, you HAVE to save each item at least once.  So, you could call it this way:

    $c->save();
    $d->save($c);

    DataMapper is smart enough not to re-save an object, so this would result in the exact same number of queries:

    $c->save();
    $d->save();
    $c->save($d);

    Finally, I hope that is example code, because you should not be using $_POST with CodeIgniter.  Instead, use $this->input->post(‘field_name’), which is more secure.

  • #503 / Feb 10, 2009 2:51pm

    easylancer

    42 posts

    Hi OverZealous.com, thanks for such a quick reply. I read the docs actually and this doesn’t exist in there, as all the examples on the save page were querying the object before it stores the relationship. All the examples i saw would do something like this

    // Get user foo
    $u = new User();
    $u->where('username', 'foo')->get();
    
    // Get country object for Australia
    $c = new Country();
    $c->where('name', 'Australia')->get();
    
    // Relate user foo to country Australia
    $u->save($c);

    It would be nice if stensi could add this as an example to the documents.

  • #504 / Feb 10, 2009 4:54pm

    tdktank59

    322 posts

    I was having problems savings relations like that…

    For some reason it would not make the link… but save the 2 tables…

  • #505 / Feb 11, 2009 4:33am

    OverZealous

    1030 posts

    DataMapper Updates

    Stensi appears to be busy right now (hopefully doing something that makes money!), so I thought I’d try something out.  I’ve been working on an overhaul of DataMapper that allows for a few new features, and improves upon the relationship model.

    These are the major changes:
    1. Now supports more customizable relationships
      ⁃ One-to-one and one-to-many relationships can be joined without a join table.  The “one” side needs to be stored as “type_id”, where type can be anything.
      ⁃ Multiple, different relationships of the same object can occur now.  For example, a User can be both an Editor and a Creator for a blog post.
      ⁃ Self-references no longer require additional models.  Just specify the fields explicitly, within the same object.
      ⁃ Relationships are defined by the name of the related field, and that field can point to any class, and use any column names (that end in _id).
      ⁃ The old technique works exactly as it did before.  No existing code should need any changes, unless it was working within DataMapper’s non-public methods.
      ⁃ Join table names are still bars_foos for non-self-references.  For self-references, the join tables are barcolumns_foocolumns, where barcolumns is the plural of the column name for bar, and foocolumns is the plural of the column name for foo.
      ⁃ See the attachments for the exact new formatting for the has_one and has_many arrays.
    2. One-to-N related objects can be joined into a query, so that the values from multiple objects can be queried at once.
      ⁃ Use the method $object->join_related($field_name, $other_fields)
      ⁃ $field_name can either be a related field, or an object.  The object will only work it $object->model is the same as it’s field_name.
      ⁃ $other_fields should be the name or names (as an array) of fields to join in this query.  It is required, and cannot be ‘*’.
    3. Because an object can be saved to multiple fields, it may be necessary to specify which field when saving or deleting the relationship.
      ⁃ For example, to save the editor User to a Post, call $post->save_editor($user) or $user->save_editedpost($post).
      ⁃ If you have the field name in a string, you can also call $post->save($user, ‘editor’).
      ⁃ If you are saving multiple objects, you can save them as $post->save(array(‘editor’ => $user)).
      ⁃ Specifying the field is ONLY necessary if the field is not the same as the name of the Model.

    What I’d like is some help with this unofficial version.  There’s over 150 lines-of-code changed in this version, and while I tested it some, I might have missed some things, or there might be edge cases I missed.  (I’m already using it on my testing server, and have reduced the number of database tables by about half just by using the in-table has_one relationships.)

    So, if you are feeling lucky, please try out the DataMapper.php included in the ZIP file.  For an example of how to use these new features, please read DataMapper Changes.rtf in the ZIP.  I’ve included a lot more information about how the new relationships work.

  • #506 / Feb 11, 2009 6:07am

    Daniel H

    197 posts

    Phil this sounds really exciting - looking forward to trying it out.

  • #507 / Feb 11, 2009 12:49pm

    bEz

    110 posts

    Is DMevolution on the horizon?
    Sounds right up my alley, although I’d still like to wrap-up my dev trials re-organizing my db to adhere to DM.

  • #508 / Feb 11, 2009 2:27pm

    tdktank59

    322 posts

    Sounds Great!!!

  • #509 / Feb 13, 2009 7:39am

    tdktank59

    322 posts

    Any idea on how we can pull columns in the join tables?

  • #510 / Feb 13, 2009 2:26pm

    macigniter

    244 posts

    First of all… great job with the update. I’ll make sure to give it a try asap.

    Until then I noticed something today that confused me…

    - Users belong to one Client, although this relation might not be set
    - Client has many Products

    $u = new User();
    $u->get_by_id($user_id);

    $u->group->get();
    $u->client->get();

    $p = new Product();
    $p->get_by_related($u->client);

    foreach ($p->all as $product) echo $product;

    What I thought was strange is the fact that if a user does not belong to a client DataMapper still spits out all products for this user.

    Shouldn’t $p->get_by_related($u->client) only return actual relations if a client was assigned to the user?

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

ExpressionEngine News!

#eecms, #events, #releases