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]
  • #571 / Feb 19, 2009 3:56pm

    OverZealous

    1030 posts

    This is one of the things I was trying to solve.  In the current, official version of DataMapper, you have to have a column for every model type when working with multiple relationships (to the same table).

    In other words, you need this as your join table:
    join_files_users
    - id NOT NULL
    - file_id NOT NULL
    - user_id
    - creator_id

    Note that they must allow nulls.  Now the queries will work.

    However, there is a big problem with this.  If you look up the creator ($file->creator->get()), that creator will not work for any relationships that were set as a user.  Assuming that Users have a relationship to Roles, this will not work:

    $creator = $file->creator->get();
    $role = $creator->role->get(); // there is no relationship here, because it will look for the column creator_id again.
    
    $user = new User();
    $user->get_by_id($creator->id);
    $role = $user->role; // this works, now

    In the updated version, you can assign the same exact model in multiple ways, just using different field names:

    class User extends DataMapper {
        $has_many = array(
            'file',
            'created_file' => array(
                'class' => 'file',
                'other_field' => 'creator'
        );
    }
    
    class File extends DataMapper {
        $has_one = array(
            'user',
            'creator' => array(
                'class' => 'user',
                'other_field' => 'created_file'
        );
    }
    
    // in controller
    $creator = $file->creator->get(); // $creator is a User class
    $user = $file->user->get(); // ditto

    What’s even better, you can create the file table like this:
    files
    - id,
    - ...
    - user_id int32, Must allow nulls
    - creator_id int32 Must allow nulls

  • #572 / Feb 19, 2009 6:20pm

    macigniter

    244 posts

    Thank you so much for your explanation Phil. I am still very new to CodeIgniter and ORM. But learning very fast and loving it. I will try to use your updated version of DataMapper with my application and let you know how it works out. Since I am new to CI and DataMapper your documentation file wasn’t that easy to comprehend compared to DM’s user guide. But I am trying my best since I really appreciate all your contributions to this great library!

  • #573 / Feb 19, 2009 9:14pm

    OverZealous

    1030 posts

    I apologize for not having better examples prepared.  My own projects have taken up a lot of time lately, so I appreciate the effort being put in by those testing it.  I know my “documentation” was fairly light.  I’ll try to get a complete example available some time soon!

  • #574 / Feb 20, 2009 8:54pm

    fancms

    20 posts

    First, thanks for this class; I’m definitely having better productivity with it!

    I’m a little puzzled over something. If I want to display all records from a table, I cannot use a select call. For example:

    //This allows me to list all users
    $u = new User();
    $u->get();
    
    //Say I want to show just their username and email
    $u = new User();
    $u->select("username,email")->get();
    //This will only list one record :-\

    Is there any way to be able to select only the needed fields? I don’t usually need every column when making a call. Any advice/direction would be appreciated! 😊

  • #575 / Feb 20, 2009 10:55pm

    OverZealous

    1030 posts

    Select works.  You might want to check the queries being run, and make sure you aren’t getting the correct results.

  • #576 / Feb 21, 2009 5:52am

    fancms

    20 posts

    D’oh! I just looked at one of my views again and realized I was using the same variable in my foreach as in the controller. That is:

    Controller

    $u = new User();
    $u->select("username,email")->get();
    //...
    $data['users'] = $u->all;

    View

    foreach($users as $u) {
    Username: $u->username
    
    Email: $u->email
    }

    I completely forgot that accessing it via $u->whatever would only show me one record. 😊 Changing it to $use in the view solved it.

    Thanks for the response, OverZealous!

  • #577 / Feb 22, 2009 11:44am

    TheBushMunky

    2 posts

    Hey, I was wondering how do I repopulate a form with its previous values if the data is validated and there is an error?

    I’ve tried using what I’ve found in DataMapper’s Validation docs and the Form Helper & Form Validation docs for CodeIgniter. I’m using the DataMapper model’s save() method to validate the data & save if valid. If the save fails, then I redisplay the form with the errors. I figured I’d use the Form Helper method set_value() to repopulate the fields as they show in the docs but that doesn’t seem to work for me. Here’s the code I have:

    Controller Method:

    function add() 
    {
        $post = new Post();
      
        $post->title = $this->input->post('title');
        $post->body = $this->input->post('body');
        $post->teaser = $this->input->post('teaser');
        $post->slug = $this->input->post('slug');
        $post->published = $this->input->post('published');
      
        // Apply Markdown on `body` text before saving.
        $post->markdown();
      
        if ($post->save()) 
        {
          $data = array(
            'title'=> $post->title,
          );
      
          $this->load->view('admin/post_created', $data);
        }
        else 
        {
          $data = array(
            'title' => 'Create Post',
            'error' => $post->error->string,
          );
      
          $this->load->view('admin/post_create', $data);
        }
    }


    And the view:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html >
    
      <head>
        <title><?=$title?></title>
        <link rel="stylesheet" href="<?=base_url()?>/media/css/admin.css" type="text/css" media="screen" />
      </head>
    
      <body>
        <div id="dashboard-wrapper">
        </div>
        
        <div id="app">
    
          <?=form_open('admin/blog/add');?>
    
              <div class="title">
                <h2>Write a new Post.</h2>
    <p>            <br />
              </div><br />
      <br />
              <div id="test" class="test"><br />
                <?=$error?><br />
              </div><br />
              <br />
              <div class="field required"><br />
                <label for="body" class="label">Content <span class="help"> And so the boy roared.</span></label><br />
                <div class="input"><?=form_textarea('body', set_value('body'));?></div>    <br />
              </div></p>
    
    <p><br />
              <div class="field required"><br />
                <label for="title" class="label">Title <span class="help">Make it pop and fizz.</span></label>  <br />
                <div class="input"><?=form_input('title', set_value('title'));?></div><br />
              </div></p>
    
    <p><br />
              <div class="field"><br />
                <label for="teaser" class="label">Teaser <span class="help">Sell the sizzle.</span></label>         <br />
                <div class="input"><?=form_input('teaser', set_value('teaser'));?></div><br />
              </div></p>
    
    <p>          <div class="field required"><br />
                <label for="slug" class='label'>Slug <span class="help">URL friendly title.</span></label><br />
                <div class="input"><?=form_input('slug', set_value('slug'));?></div><br />
              </div></p>
    
    <p>          <div class="field"><br />
                <?=form_label('Published','publish', array('class' => 'label'));?>    <br />
                <?=form_checkbox('publish', 'publish', TRUE);?><br />
              </div></p>
    
    <p><br />
              <div class="field"><br />
                <label class="label"> </label> <br />
                <div class="input"><?=form_submit('create', 'Save');?></div> <br />
              </div></p>
    
    <p>          <!-- Does set value work? --><br />
              <?=set_value('body') ?><br />
              <br />
            <?=form_close();?><br />
        </div></p>
    
    <p>  </body><br />
      <br />
    </html>

    Aside from not repopulating the user’s input if the form doesn’t pass validation, it works 😛 But I’d really like to be able to repopulate the data the user already entered, especially if some of it was valid

  • #578 / Feb 22, 2009 11:56am

    OverZealous

    1030 posts

    For future reference, please be a little more selective in what you post - obviously we don’t need the whole web page.

    When using DataMapper, you don’t have to resort to any tricks for your form.  Simply pass the same object in before or after it is edited:

    // controller
    function edit($id = NULL) {
        $post = new Post();
        // do security checks, etc.
        if( ! is_null($id)) {
            // load in the object to be edited
            $post->get_by_id($id);
            // verify input
        } else if($this->input->post('id') !== FALSE) {
            // load in the already edited object
            $post->get_by_id($this->input->post('id'));
            // save form data, validate, etc.
            // redirect on successful save
        } else {
            show_error("Invalid id.");
        }
        $this->load->view('edit_post', array('post' => $post));
    }
    
    
    // in view
    ?>
    <input type="text" name="title" id="title" value="<?= htmlspecialchars($post->title) ?>"> <?= $post->error->title ?>
    <?
    // etc.

    You can expand this to be a little smarter, if necessary.  You can even use the same form for adding new ones, simply don’t throw an error if the ID is not passed.  On saving, the id will be 0, so you can check for that if necessary.  Calling ->save() will work for new or existing objects, and you can get the id of the saved object as $post->id on new saves as well.

  • #579 / Feb 22, 2009 12:25pm

    TheBushMunky

    2 posts

    Oh, great, thanks! That’s actually alot simpler than I thought it would be. Sorry about being so verbose and thanks for the tips 😊

  • #580 / Feb 22, 2009 10:01pm

    tdktank59

    322 posts

    OverZealous I put some thought into why my single join table thing isnt work. (your new method with relations in the main table).

    The reason why $asd->author->get(); as show below would not work is because there is no model named author… So my question to you is how are we to get author_id out of the dqip and relate it to the proper user.

    This is where im at a loss… Since I know trying to get the author does not work.

    Would I have to grab the author_id and manually relate the author_id to the user table?

    Heres the example:

    Code:

    $asd = new Dqip();
    $asd->where('id',$dqip_id)->get();
    $asd->data_source->get(); // Does work since there is a data_source model (not related within the dqip table)
    $asd->author->get(); // Does not work since there is no author model

    user model:

    var $has_many = array(  "brainstorm",
                                "role",
                                "team",
    
                                /* DQIP User Fields */
                                "dqip_author"       => array (  'class' => 'dqip',
                                                                'other_field' => 'author'),
                                "dqip_dciu_staff_1" => array (  'class' => 'dqip',
                                                                'other_field' => 'dciu_staff_1'),
                                "dqip_dciu_staff_2" => array (  'class' => 'dqip',
                                                                'other_field' => 'dciu_staff_2')
                             );

    Dqip Model:

    var $has_one = array( "author"          => array(   'class' => 'user',
                                                            'other_field' => 'dqip_author' ),
    
                              "dciu_staff_1"    => array(   'class' => 'user',
                                                            'other_field' => 'dqip_dciu_staff_1'),
    
                              "dciu_staff_2"    => array(   'class' => 'user',
                                                            'other_field' => 'dqip_dciu_staff_2')
                              );
  • #581 / Feb 22, 2009 10:54pm

    OverZealous

    1030 posts

    Are you using the second updated one I posted?  That might be the problem.  The earlier version required that ‘join_other_as’ be set, while the second one requires that ‘other_field’ is set (like you have).

    You don’t need to have a model named ‘author’ for it to work.  The code inside DM looks up the “model” based on ‘join_self_as’, ‘other_field’, or $this->model in that order.

    Basically, when you call $asd->author->get(), this is what happens:
    * The property author triggers a look up to determine which class to instantiate.  In this case, it looks at $has_one[‘author’], and sees the class is User (lowercase user is OK here).
    * A blank User is created.  This User is told that its parent’s id is $this, and it is related through other_field (in this case, dqip_author).
    * When you call get(), DM notices the parent information, and runs the query based on that.  It looks up $has_many[‘dqip_author’] to determine how to query.
    * dqip_author says the field to relate on is author (because that’s the other_field name)
    * The table is determined to be dqips, because the field author_id is available on that table.
    * Finally, the tables are joined and the query proceeds.

    Assuming you are using the updated version, the only place you would see an error about join_dqips_users is if author_id is not on the dqips table.

    Let me know if that helps any.  Otherwise, I’ll happily take a look at your server again 😉, because I want to make sure the bug isn’t in my code!

  • #582 / Feb 22, 2009 11:39pm

    Yman

    7 posts

    can anyone see what is wrong with my code here:

    foreach($latest_entry->all as $e){
        
        echo "Reference No:" . $e->entry_no;
        $e->product->get();   //I'm accessing relationship to 
                              // "product", and Yes, Product model exist
        echo "Product:" . $e->product->name;
        echo "Knowledge Fragment:" . $e->know_fragment;
        echo "Severity Level:" . $e->severity;
        }

    It get error saying “Call to a member function get() on a non-object”

    and also, am i doing the saving relationships correctly?

    $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');
            
            //saving the relationships
            $c1 = new Horizontal();
            $c1->get_by_name($this->input->post('horizontal'));
            $c2 = new Product();
            $c2->get_by_name($this->input->post('product'));
            $c3 = new Descriptor();
            $c3->get_by_name($this->input->post('descriptor'));
            $c4 = new Dataresource();
            $c4->get_by_name($this->input->post('dataresource'));
            $c5 = new Ppnbg();
            $c5->get_by_name($this->input->post('ppnbg'));
            $c6 = new Persona();
            $c6->get_by_name($this->input->post('persona'));
            $c7 = new Maintask();
            $c7->get_by_name($this->input->post('maintask'));
            $c8 = new Rawdatatype();
            $c8->get_by_name($this->input->post('rawdatatype'));
            
            $n->save(array($c1, $c2, $c3, $c4, $c5, $c6, $c7, $c8));
  • #583 / Feb 23, 2009 6:46am

    tdktank59

    322 posts

    @overzealous

    I had no clue you released a new version lol You should put some version numbers on yours so we know whats what lol.

    Other than that ill let you know if it fixes it.

    Update

    Fixed the problem however id like to point out something you may want to look at.
    Notice all the user table joining looks like 3 times for each user get i want to grab.

    0.0002     SELECT * FROM `dqips` LIMIT 1

    0.0001     SELECT *
    FROM (`dqips`)
    WHERE `id` = ‘1’

    0.0001     SELECT * FROM `data_sources` LIMIT 1

    0.0001     SELECT `data_sources`.*
    FROM (`data_sources`)
    LEFT JOIN `join_data_sources_dqips` as join_data_sources_dqips ON `data_sources`.`id` = `join_data_sources_dqips`.`data_source_id`
    LEFT JOIN `dqips` as dqips ON `dqips`.`id` = `join_data_sources_dqips`.`dqip_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `data_sources`.*
    FROM (`data_sources`)
    LEFT JOIN `join_data_sources_dqips` as join_data_sources_dqips ON `data_sources`.`id` = `join_data_sources_dqips`.`data_source_id`
    LEFT JOIN `dqips` as dqips ON `dqips`.`id` = `join_data_sources_dqips`.`dqip_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT * FROM `users` LIMIT 1

    0.0001     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`author_id`
    WHERE `dqips`.`id` = ‘1’

    0.0002     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`author_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`dciu_staff_1_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`dciu_staff_1_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`dciu_staff_2_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`dciu_staff_2_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`author_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`dciu_staff_1_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `users`.*
    FROM (`users`)
    LEFT JOIN `dqips` as dqips ON `users`.`id` = `dqips`.`dciu_staff_2_id`
    WHERE `dqips`.`id` = ‘1’

    0.0001     SELECT `data_sources`.*
    FROM (`data_sources`)
    LEFT JOIN `join_data_sources_dqips` as join_data_sources_dqips ON `data_sources`.`id` = `join_data_sources_dqips`.`data_source_id`
    LEFT JOIN `dqips` as dqips ON `dqips`.`id` = `join_data_sources_dqips`.`dqip_id`
    WHERE `dqips`.`id` = ‘1’

  • #584 / Feb 23, 2009 2:31pm

    wolffc

    14 posts

    Is it possible to give an order column to the joining table?  Lets say a user can pick 3 of 10 options and set a specific order.  Would they be inserted and retrived in the same order?


    Thanks

    I’ve been toying with this idea of building in methods that access additional fields in the relationship tables..

    essentially though, you can add whatever fields you like, in your linking table as long as you have the id, model1_id, model2_id fields..

    so say you want to get a users groups, which would have a sort order, you could add in an order_number column on the groups_users table, and then (with a join specified), you can try

    $user = new User();
    $user->where('id',$userID)->get();
    $user->group->order_by('groups_users.order_number', 'asc');
    $user->group->get();

    does that make sense?.. you just have to literally specify the relationship table name for now.

    CC

    So, getting the data is not a problem.  My problem is actually setting the order.  I can write a sql query to do it but was wondering if there was a way to actaully set the order using the save method.  Is it possible to actually save an order field in my joining table?

  • #585 / Feb 23, 2009 2:58pm

    DominixZ

    23 posts

    Today I do my project with DataMapper and I have these models.
    - Bookmark
    - User
    - Tag
    Bookmark has_many Tag
    Tag has_many Bookmark
    User has_many Bookmark
    Bookmark has_one User

    and my question. Is it possible to delete relationship with one step? Now, I must use code like this to complete delete relationship
    $bookmark->user->get();
    $bookmark->tag->get();

    $bookmark->delete($bookmark->tag);
    $bookmark->delete($bookmark->user);
    $bookmark->delete();

    Please lead me the right way to complete this.

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

ExpressionEngine News!

#eecms, #events, #releases