Cphalcon: Related models not saved when querying them first

Created on 31 Jul 2019  路  4Comments  路  Source: phalcon/cphalcon

  • Phalcon version: 3.4.4
  • PHP Version: 7.2.19
  • Operating System: CentOS 7
  • Installation type: installing via package manager
  • Server: Apache, but also on the command line
  • Other related info (Database, table schema): MySQL 5.7.27

I'm opening this issue/bug report on request in this topic: https://forum.phalconphp.com/discussion/19903/robot-parts-not-updated-after-querying-parts-first

Please have a look at the code below. It's the default Robots/Parts/RobotsParts setup. Adding parts to the robot works fine. But when querying the parts first using $robot->parts and then adding new parts, nothing is saved to the database.

I commented the code below to illustrate what goes wrong. The models are stored in MySQL tables with cascading foreign keys.

<?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
{
    /**
     * Test sequence
     */
    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);
        }
    }

    /**
     * Delete everything in the database,
     * then add 1 robot with 2 parts.
     */
    public function initAction()
    {
        Robot::find()->delete();
        Part::find()->delete();
        // The link table (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
    }

    /**
     * Add 2 more parts
     */
    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.
    }

    /**
     * Add 2 more parts, but query the existing parts first.
     */
    public function bugAction()
    {
        $part5 = new Part;
        $part5->name = "finger";

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

        $robot = Robot::findFirstByName("bob");

        // Query the parts, for some reason,
        // for example to check if the parts are in the db already...
        $temp = $robot->parts;

        $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...
        }
    }
}

Running the test:

$ 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)

Expected: 1 robot with 6 parts
Actual: 1 robot with 4 parts

This feels like a bug to me. Instead of using $robot->parts one can use $robot->getRelated('parts') or $robot->getParts() to work around this problem.

bug low

Most helpful comment

@ruudboon, I think I've already fixed this issue for v4 in #14035.
There were caching issues, where the queried related records and relations were stored along with the new ones.

All 4 comments

~I think this issue is also happening in V4.~

@gwijnja do you have the possibility to test this under v4-beta.1 ?

@ruudboon, I think I've already fixed this issue for v4 in #14035.
There were caching issues, where the queried related records and relations were stored along with the new ones.

Looks like it's fixed in v4 indeed.

Was this page helpful?
0 / 5 - 0 ratings