Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Cascade restore does not work
  • Hello together

    i was trying the orm package and everything works like a charm, except for restoring soft deleted models, where cascade-delete is activated.

    If i soft-delete a person, the user connected to the person gets a DeleteDate too.
    But if i restore the person, the code crashes, if there is cascade-delete activated:

    Fatal error: Call to a member function restore() on string in /volume1/web/testapp/packages/orm/classes/model/soft.php on line 238

    238 model->restore($cascade_restore);

    I don't really understand how the code works here...

    Does anybody know an answer? :)

    Greetings
    Danny

  • These are my two models:

    class Person extends \Orm\Model_Soft
    {
    protected static $_has_one = array('User'=>array('key_from'=>'Id','model_to'=>'Model\\User','key_to'=>'PersonId','cascade_delete'=>true));

    protected static $_soft_delete = array('deleted_field'=>'DeleteDate','mysql_timestamp'=>true);}


    class User extends \Orm\Model_Soft
    {

    protected static $_soft_delete = array('deleted_field'=>'DeleteDate','mysql_timestamp'=>true);

    }

  • Can you add this line in front of line 238, and tell me the result?

    if ( ! is_object($model)) { var_dump($model); die(); }

    It tries to retrieve the related objects there so it can remove their deletedate, but instead of a model object, a string seem to be returned.
  • Hey Harro,

    thanks for your reply :)

    The result is:

    string(1) "3"


    It's the userId which needs to get undeleted.I tested it with a user where user.Id <> user.PersonId.

    Greetings
    Danny
  • Ok, so it returns the field value rather than the object.

    This might have to do with the fact that your User model doesn't seen to have a relation definition for the Person model.

    In ORM, you always have to define the relation both ways, in your case a has_one "person to user", and a belongs_to "user to person", assuming that your User object contains the foreign key.
     
  • I added

    protected static $_belongs_to = array('Person'=>array('key_from'=>'PersonId','model_to'=>'Model\\Person','key_to'=>'Id','cascade_delete'=>true));

    to my Model\User (with and without 'cacade_delete'=>true) and

    $person = Person::find_deleted(4)
    $person->undelete();

    still returns

    string(1) "5"


    Greetz
    Danny
  • Hmm, ok.

    It does a get() there on the relation object, which must return either NULL or a model object. Since it returns a value instead, it suggests it does a get() on a model object instead.

    Can you replace it with:

    if ( ! is_object($model)) { var_dump($rel); die(); }

    And tell me what kind of object is dumped?
  • It returns

    object(Orm\HasOne)#38 (9) {
    ["singular":protected]=>
    bool(true)
    ["name":protected]=>
    string(4) "User"
    ["model_from":protected]=>
    string(12) "Model\Person"
    ["model_to":protected]=>
    string(10) "Model\User"
    ["key_from":protected]=>
    array(1) {
    [0]=>
    string(2) "Id"
    }
    ["key_to":protected]=>
    array(1) {
    [0]=>
    string(8) "PersonId"
    }
    ["conditions":protected]=>
    array(0) {
    }
    ["cascade_save":protected]=>
    bool(true)
    ["cascade_delete":protected]=>
    bool(true)
    }

  • This is the correct object. I am clueless atm, I don't see how that objects' get() method can ever return a string.

    You haven't overloaded any query(), get() or get_one() methods in your model? You are using at least v1.8 of Fuel, and of the packages?
  • Can you enable the profiler in your config, and enable database profiling in the database config?

    And then run your code, and post the generated SQL that returns that "5" value?
  • No, i use the models "as they are" because at the moment i am really new in this orm thing. Before i always used plain sql queries :-)

    These SQL queries are done:

    SELECT `t0`.`Id` AS `t0_c0`, `t0`.`CustomerId` AS `t0_c1`,
    `t0`.`Firstname` AS `t0_c2`, `t0`.`Lastname` AS `t0_c3`,
    `t0`.`DateOfBirth` AS `t0_c4`, `t0`.`Gender` AS `t0_c5`,
    `t0`.`LanguageId` AS `t0_c6`, `t0`.`InsertDate` AS `t0_c7`,
    `t0`.`InsertUserId` AS `t0_c8`, `t0`.`UpdateDate` AS `t0_c9`,
    `t0`.`UpdateUserId` AS `t0_c10`, `t0`.`DeleteDate` AS `t0_c11` FROM
    `person` AS `t0` WHERE `t0`.`DeleteDate` IS NOT null AND `t0`.`Id` = '4'
    LIMIT 1

    This one returns the 5:
    SELECT `t0`.`Id` AS `t0_c0`, `t0`.`PersonId` AS `t0_c1`, `t0`.`Username`
    AS `t0_c2`, `t0`.`Password` AS `t0_c3`, `t0`.`DeleteDate` AS `t0_c4`
    FROM `user` AS `t0` WHERE `t0`.`PersonId` = '4' LIMIT 1
  • Ah, shoot, think I found it.

    foreach ($rel->get($this) as $model)
    {
        $model->restore($cascade_restore);
    }

    assumes that get() returns an array you can iterate over. But for singular relations like HasOne, it returns a single object.

    Can you replace that with:

    $models = $rel->get($this);
    is_array($models) or $models = array($models);
    foreach ($models as $model)
    {
        $model->restore($cascade_restore);
    }

    and see if that fixes your problem?
  • Hey Harro

    Exception now is:

    PKGPATH/orm/classes/model.php @ line 962

    Orm\FrozenObject [ Error ]:
    No changes allowed.

    962 throw new FrozenObject('No changes allowed.');


    Code in soft.php looks like this now:

    if (get_class($rel) != 'Orm\ManyMany')
    {
    $model_to = $rel->model_to;
    $model_to::disable_filter();

    $models = $rel->get($this);
    is_array($models) or $models = array($models);

    foreach ($models as $model)
    {
    $model->restore($cascade_restore);
    }

    $model_to::enable_filter();
    }

  • HarroHarro
    Accepted Answer
    Do you have the restore cascade defined on both relations?

    If so, it could be that you're now in an update loop (A->B->A...), Frozen means an update is being updated at the moment, so new updates are allowed, which could happen if it cascades back from B to A while A is already being restored.

    Can you remove it from the belongs_to relation?
  • Hey Harro

    you're right, i had "cascade_delete" activated in Model\User, which makes no sense at all, because if the user gets deleted, the person behind it should not automatically be deleted to.

    Now the code works!

    I also tested it, if Person has no cascade_delete activated in the relationship to User and this works too.

    Thank you very very much for your support!

    Greetings
    Danny
  • Cool, thanks for the feedback.

    I'll commit the fix for Model_Soft later today.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion