We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Saving related models

Hi,

I have two questions on saving related Models. Please see "has-many relation" example at https://docs.phalcon.io/en/latest/reference/models.html#storing-related-records.

1) Why do I arrive in Album::afterSave() before related models Songs are saved? To me it looks like an incorrect behaviour, as I might want to perform additional actions depending on the outcome of saving of related objects.

2) The following assignment of related Models works as expected:

$album->songs = $songs;

However, the following does not save any Related models:

class Album
{
    public function beforeSave()
    {
        $this->songs = $songs;
    }
}

This looks like a bug.

Any comments?

Thanks!

1) Agreed. Album::save() would return after all the related models are saved as well - while it's not ideal, you could put logic outside the model that does your clean-up. Or, failing that, you might try overloading save:

class Album
{
    public function save()
    {
        if(parent::save())
        {
            //do your clean up here
        }
    }
}

2) beforeSave() doesn't accept any arguments, so $songs is not defined.



51.4k

Re #1 - well, I'd hate overloading. But, so far, it's been a prescribed recommendation for all the problems I'm having with Phalcon. Getting used to that.

Re #2 - of course $songs isn't arriving as function argument. I omitted a whole chunk of code. Here's what I should have written:

class Album
{
    public function beforeSave()
    {
        $songs = [];

        // Create a first song
        $songs[0] = new Songs();
        $songs[0]->name = 'Star Guitar';
        $songs[0]->duration = '5:54';

        // Create a second song
        $songs[1] = new Songs();
        $songs[1]->name = 'Last Days';
        $songs[1]->duration = '4:29';
        $this->songs = $songs;
    }
}

The point is that, somewhere between $album->save() and $album->beforeSave() , something happens in the modelManager that makes it ignore related models set in beforeSave() phase.

I have also tried the following, which best illustrates the bug:

class Album
{
    public function beforeSave()
    {
        $songs = [];

        // Create a first song
        $songs[0] = new Songs();
        $songs[0]->name = 'Song 2';

        $this->songs = $songs;
    }
}

$album = new Album;
$songs = [];
$songs[0] = new Songs();
$songs[0]->name = 'Song 1';

$album->songs = $songs;
$album->save();

In that case above 'Song 1' gets saved, even though it's overridden in beforeSave() method.

Thanks



51.4k

Just FYI, the issue has been updated:

https://github.com/phalcon/cphalcon/issues/1616

Thanks

Why do you need to override in beforeSave(). I ask not to question your logic, but to see if there's another way around this.



51.4k

I prefer beforeSave() to encapsulate all Model's dependent logic in the Model class itself.

I like the luxury of onBeforeCreate(), onBeforeUpdate() and other callbacks. That way I have granular control over what should happen to related models depending on various circumstances. After all, your model may fail validation and you won't even need all those instances of Song assigned to Album::$_related.