Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Belongs_to relation not saved/altered when calling save() after deleting a related model [1.7/develop] #283

Open
philipptempel opened this issue Jul 23, 2013 · 7 comments

Comments

@philipptempel
Copy link

Assume two models, \Model\Record and \Model\Group, with a \Model\Record belongs_to \Model\Group, \Model\Group has_many \Model\Record.

When doing something like the following:

<?php
// Get the record
$record = \Model\Record::find(<some arbitrary ID>);

// Change the assigned group
$record->group = \Model\Group::find(<some arbitrary ID>);

/*
 * Assign some other properties and related data here, too
 */

// Save at the end to save on DB-queries
$record->save()

then $record->group will be changed to the new ORM-object, but the property of \Model\Record keeping the reference to its assigned group is not updated.

An exemplary result of \Debug::dump($record->to_array()); before and after assigning the group as well as after calling save() is listed below:

Before changing the group

     surname (String): "Tempel" (6 characters)
     prename (String): "Philipp" (7 characters)
     archived (Boolean): false
     created_at (Integer): 1374585392
     updated_at (Integer): 1374587495
     archived_at : null
     record_id (String): "1" (1 characters)
     rel_group_id (String): "1" (1 characters)
     meta (Array, 82 elements) ↵
     group (Array, 7 elements) ↵
         group_id (String): "1" (1 characters)
         name (String): "Student" (7 characters)
         slug (String): "student" (7 characters)
         protected (Boolean): true
         created_at (Integer): 1374478794
         updated_at (Integer): 1374478794

After changing the group

     surname (String): "Tempel" (6 characters)
     prename (String): "Philipp" (7 characters)
     archived (Boolean): false
     created_at (Integer): 1374585392
     updated_at (Integer): 1374587495
     archived_at : null
     record_id (String): "1" (1 characters)
     rel_group_id (String): "1" (1 characters)
     meta (Array, 82 elements) ↵
     group (Array, 6 elements) ↵
         group_id (String): "2" (1 characters)
         name (String): "Mitarbeiter" (11 characters)
         slug (String): "mitarbeiter" (11 characters)
         protected (Boolean): true
         created_at (Integer): 1374478794
         updated_at (Integer): 1374478794

After save()

     surname (String): "Tempel" (6 characters)
     prename (String): "Philipp" (7 characters)
     archived (Boolean): false
     created_at (Integer): 1374585392
     updated_at (Integer): 1374587599
     archived_at : null
     record_id (String): "1" (1 characters)
     rel_group_id (String): "1" (1 characters)
     meta (Array, 86 elements) ↵
     group (Array, 6 elements) ↵
         group_id (String): "2" (1 characters)
         name (String): "Mitarbeiter" (11 characters)
         slug (String): "mitarbeiter" (11 characters)
         protected (Boolean): true
         created_at (Integer): 1374478794
         updated_at (Integer): 1374478794

If save() is called right after changing the group, it works perfectly, however.

Using 1.6/master changes the output of the last \Debug::dump to rel_group_id (String): "2" (1 characters) which is the expected behavior.

@philipptempel
Copy link
Author

I was just talking with uru on #fuelphp and we narrowed the issue a littler further down:

The problem of non-saved changed relations arises in my case when another relation is deleted before or after changing other relations. Sample code is as follows:

<?php

// Get the record to edit from the DB
$record = \Model\Record::query()
  ->where('id', '=', '1')
  ->related('group')
  ->related('meta')
  ->get_one();

// Change the record's group according to a form input
$record->group = \Model\Group::find(\Input::post('group_id'));

// Delete the old meta-fields (this might not be best practice, but should cause the problem anyhow)
foreach ( $record->meta as $k => $meta )
{
  // Unsetting the meta was added on advice from uru, but did not change the result
  unset($record->meta[$k]);
  $meta->delete();
}

// Then, add new meta values to the record
foreach ( \Input::post('meta', array()) as $field_id => $value )
{
  // This just checks whether there is a value and if it's a valid Profilefield
  if ( $value && $field = \Model\Profilefield::find($field_id) )
  {
    $meta = new \Model\Recordmeta(array('value' => $value));
    $meta->field = $field;
    $record->meta[] = $meta;
  }
}

// This will change the meta fields, but will not change the group assigned to the record
$record->save();

Used models are related like so:

record belongs_to group
record has_many meta
group many_many profilefield
group has_many record
meta belongs_to record, profilefield
profilefield many_many group

Even if I first change the meta-fields and then change the group, it still does not save/alter the assigned group.

@awgneo
Copy link

awgneo commented Dec 10, 2013

Same basic issue here :/ I have re-order all of my relationship assignments to after metadata setting to avoid this issue for now. I am using the latest 1.7/master. 1.8/develop also has the same issue.

@awgneo
Copy link

awgneo commented Dec 12, 2013

Grrr..... re-ordering the assignment of metadata still leads to unpredictable results. Of course, you can also avoid this by setting the foreign ids directory instead of assigning objects, but this kind of defeats the point of having an ORM.

@WanWizard
Copy link
Member

There were some fixes today related to this, are you using an up to date 1.8/develop? An intermediate action on the object would cause the original relation data to be reset, causing your new records not to be seen as new anymore (and therefore not saved).

@awgneo
Copy link

awgneo commented Dec 12, 2013

Hrm... I don't see any recent commits other than the one to classes/manymany.php. I will look out for it though! Thanks for the update.

@WanWizard
Copy link
Member

Ah, sorry, my bad.

It was discussed today in IRC, I tested it but didn't commit it because someone else was already working on it and would send it in as a PR. Which I haven't seen yet.

@webfacer
Copy link

webfacer commented Mar 8, 2014

same issue here this helped me out http://fuelphp.com/forums/discussion/comment/17145

EDIT:
i just modified it a little bit for using it even if no relation is generated. It means when no model is selected it would throw an error that the child model is empty. here how i use it:

public function action_edit( $id )
{
    // gets newsletter tabel with the articles relation
    $newsletter = \Model_Newsletter::query()->where( 'id', $id )->related( 'articles' )->get_one();

    // gets only articles for selecting relation
    $articles = \Model_Article::find( 'all' );

    if( $post = \Fuel\Core\Input::post() )
    {
        $model = \Model_Newsletter::find( $id );
        $model->title = $post['title'];

        if( isset( $post['articles'] ) && !empty( $post['articles'] ) )
        {
            $new_relation_models = array();
            foreach( $post['articles']['id'] as $key => $value )
            {
                if( $post['articles']['id'][$key] )
                {
                    $new_relation_models[ $value ] = \Model_Article::find( $value );
                }
                else
                {
                    unset( $post['articles']['id'][$key] );
                }
            }

            foreach( $model->articles as $new_relation_model )
            {
                if( !in_array( $value, $post['articles']['id'] ) )
                {
                    unset( $model->articles[ $value ] );
                }
            }

            $model->articles = $new_relation_models;

            if( $model->save() )
            {
                return \Fuel\Core\Response::redirect( 'admin/newsletters/edit/' . $newsletter->id );
            }
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants