avenirer / CodeIgniter-MY_Model

Base model (MY_Model) for the Codeigniter framework.
325 stars 204 forks source link

Using with_* in a Has Many Pivot relationship does not return an array of objects #257

Open ghost opened 7 years ago

ghost commented 7 years ago

Hello,

I was recently doing some tests regarding the model relationships and I noticed that when there is a Has Many Pivot relationship, the relationship key in the returning object is not an array of objects, but an object itself (an "object of objects" you might say).

For example, let's say I have a 'User' model and a 'User_group' model, and in my database I have a pivot table where I store the user ID and the group ID.

So, if I wanted to retrieve a user with its group(s), I would set the following relationship in the 'User_group' model:

$this -> has_many_pivot['groups'] = array(
            'foreign_model' => 'User_group_model',
            'pivot_table' => 'user_group_user',
            'local_key' => 'id',
            'pivot_local_key' => 'user_id',
            'pivot_foreign_key' => 'user_group_id',
            'foreign_key' => 'id',
            'get_relate' => TRUE
        );

Now, if I var_dump() the get() function for the user with ID 1, I get the following (FYI, this is just a test table):

object(stdClass)[60]
  public 'id' => string '1' (length=1)
  public 'email' => string 'test@test.com' (length=13)
  public 'groups' => 
    object(stdClass)[63]
      public '1' => 
        object(stdClass)[64]
          public 'id' => string '1' (length=1)
          public 'name' => string 'admin' (length=5)
      public '2' => 
        object(stdClass)[65]
          public 'id' => string '2' (length=1)
          public 'name' => string 'members' (length=7)

As you can see, if I wanted to access the first group of the user like $user -> groups[0], that would give me an error.

I actually think I've found the lines where this 'bug' (I'm just assuming it's a bug) is originating: In the join_temporary_results() function

if (isset($pivot_table)) {
                        $the_local_key = $result_array[$pivot_local_key];
                        if (isset($get_relate) and $get_relate === TRUE) {
                            $subs[$the_local_key][$the_foreign_key] = $this -> {$relation['foreign_model']} -> where($foreign_key, $result[$foreign_key]) -> get();
                        }
                        else {
                            $subs[$the_local_key][$the_foreign_key] = $result;
                        }
                    }
                    else {
                        if ($type == 'has_one') {
                            $subs[$the_foreign_key] = $result;
                        }
                        else {
                            $subs[$the_foreign_key][] = $result;
                        }
                    }

So, if there's a pivot table, the result is pushed into the $subs array at a certain key ($the_foreign_key), whereas if there's a 'has_many' relationship it is only pushed into the array without specifying any key.

Later on, in the _prep_after_read() function, this line causes the relationship data to be transformed into an object because of having specific keys: json_decode(json_encode($data), FALSE)

I apologize in advance for the length of this post, but I wanted to be as clear as possible and also to address the problem top to bottom.

phillipplum commented 6 years ago

Look at this issue: https://github.com/avenirer/CodeIgniter-MY_Model/issues/97