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

Robot parts not updated after querying parts first

I'm confused. Please have a look at the code below. It's the default robots/parts setup, with a hasManyToMany from robots to parts. I can add parts to a robot just fine. But if I query the parts just before adding new parts, nothing happens. I commented the code to illustrate what goes wrong. I'm not sure if this is expected behaviour or a bug related to i.e. the Model's dirtyState.

The models are stored in MySQL tables with cascading foreign keys. Here are the 3 model classes:

These are the model classes and my test code:

<?php

class Robot extends \Phalcon\Mvc\Model
{
    public $id;
    public $name;

    public function initialize()
    {
        $this->setSource('robots');
        $this->hasManyToMany('id', RobotsParts::class, 'robot_id', 'part_id', Part::class, 'id', ['alias' => 'parts']);
    }
}
<?php

class RobotsParts extends \Phalcon\Mvc\Model
{
    public $id;
    public $robot_id;
    public $part_id;
}
<?php

class Part extends \Phalcon\Mvc\Model
{
    public $id;
    public $name;

    public function initialize()
    {
        $this->setSource('parts');
    }
}
<?php

use Phalcon\Cli\Task;

class MainTask extends Task
{
    public function initAction()
    {
        Robot::find()->delete();
        Part::find()->delete();
        // RobotsParts has cascading foreign keys,
        // so they will be deleted by MySQL.

        $part1 = new Part;
        $part1->name = "arm";

        $part2 = new Part;
        $part2->name = "leg";

        $robot = new Robot;
        $robot->name = "bob";
        $robot->parts = [$part1, $part2];
        $robot->save(); // Works as expected
    }

    public function addAction()
    {
        $part3 = new Part;
        $part3->name = "hand";

        $part4 = new Part;
        $part4->name = "foot";

        $robot = Robot::findFirstByName("bob");
        $robot->parts = [$part3, $part4];
        $robot->save(); // Works as expected, Bob now has 4 parts.
    }

    // Basically the same as addAction()
    public function bugAction()
    {
        $part5 = new Part;
        $part5->name = "finger";

        $part6 = new Part;
        $part6->name = "toe";

        $robot = Robot::findFirstByName("bob");
        $temp = $robot->parts; // Query the parts, for some reason. Not used here.

        $robot->parts = [$part5, $part6];
        var_dump($robot->save()); // Returns true, but nothing is added to the db.

        foreach ($robot->getMessages() as $message) {
            printf("%s\n", $message); // No messages either...
        }
    }

    public function testAction()
    {
        $this->initAction();
        $this->addAction();
        $this->bugAction();

        $robot = Robot::findFirstByName("bob");
        foreach ($robot->parts as $part) {
            printf("%s (id %d)\n", $part->name, $part->id);
        }
    }
}
$ php app/cli.php test
/home/gerben/public_html/link/app/tasks/MainTask.php:52:
bool(true)
arm (id 68)
leg (id 69)
hand (id 70)
foot (id 71)

Why are the $part5 and $part6 ignored? Is this a bug or expected behavior?



10.1k
Accepted
answer

I think I saw this behaviour before maybe this indeed a bug with the magic settters. Could you try getting the relations with getRelated(‘parts’) ?

Thanks, that works indeed, so at least I can continue with my project now. But it feels a bit like a workaround...



10.1k

Yes, this should be adresssed. Would you mind opening an issue in github with these examples?

edited Jul '19

Done: https://github.com/phalcon/cphalcon/issues/14270

Thanks for helping out Ruud.



10.1k

anytime and thnx for reporting