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

Parent-Child tree relationship Model

Hello guys! I'm making a little web-app with Phalcon, but I got a trouble :-(

To simplify my situation, let's say I have

Robots(id, name) RobotsParentChild(id_parent_robot, id_child_robot)

That relations is just "one level".

In my Controller when I try to create a new Robot or Updating an existint Robot, I do something like this:

EDIT:

$robot = ($id === null) ? new Robots() : Robots::findFirstById($id);
if ($id === null) {
  $robot_parent_child = new RobotsParentChild();
  $robot_parent_child->id_child_robot = $robot->id;
} else {
  $robot_parent_child = RobotsParentChild::findFirstById($id);
  $robot_parent_child->id_child_robot = $id;
}
$robot_parent_child->id_parent_robot = $my_id;
$robot->RobotsParentChild = $robot_parent_child;

Here is the initialize() method of the RobotsParentChild Model:

    public function initialize()
    {
        $this->setSchema("myschema");
        $this->setSource("robots_parent_child");
        $this->belongsTo('id_parent_robot', '\Robots', 'xid', ['alias' => 'Robots']);
        $this->belongsTo('id_child_robot', '\Robots', 'xid', ['alias' => 'Robots']);
    }

Now it creates correctly, but don't update the id_parent_robot witht the $my_id value.



13.8k

I have another Model like

RobotsInfo(id, id_robot, weight, size, color)

And that table is getting populated correctly...



13.8k

If after this line $robot->RobotsParentChild = $robot_parent_child; I do this:

var_dump($robot->RobotsParentChild->id_parent_robot);
var_dump($robot->RobotsParentChild->id_child_robot);
exit();

C:\xampp\htdocs\phalcon\webapp\app\controllers\RobotsController.php:115:string '32' (length=2) C:\xampp\htdocs\phalcon\webapp\app\controllers\RobotsController.php:116:string '47' (length=2)

And in my database, I got the old values (when Robot was created): 31, 47, so id_parent_robot is not being updated correctly.

At the very end, I use the save() method, in this way: $robot->save();

Where is the issue?



43.9k
edited Jan '18

Hi,

I think that come from

$robot->RobotsParentChild = $robot_parent_child;

try to comment this line



43.9k
edited Jan '18

Note that your relations are not clear, use (these are my personal conventions)


    public function initialize()
    {
        $this->setSchema("myschema");
        $this->setSource("robots_parent_child");
        // with both relations aliased as Robots, it's ambigous, and
        // each relation is belong_to one Robot (only) so I use no plurals here
        $this->belongsTo('id_parent_robot', '\Robots', 'xid', ['alias' => 'parentRobot']);
        $this->belongsTo('id_child_robot', '\Robots', 'xid', ['alias' => 'childRobot']);
    }


13.8k

Hi,

I think that come from

$robot->RobotsParentChild = $robot_parent_child;

try to comment this line

Hi @le51, thanks for answering. Why? That's the mapping. robot_parent_child contains a RobotsParentChild valid Object. If I comment that line I will broke the insert too.

Please, could you explain why you are suggesting to comment that line?



13.8k

Note that your relations are not clear, use (these are my personal conventions)


   public function initialize()
   {
       $this->setSchema("myschema");
       $this->setSource("robots_parent_child");
      // with both relations aliased as Robots, it's ambigous, and
      // each relation is belong_to one Robot (only) so I use no plurals here
       $this->belongsTo('id_parent_robot', '\Robots', 'xid', ['alias' => 'parentRobot']);
       $this->belongsTo('id_child_robot', '\Robots', 'xid', ['alias' => 'childRobot']);
   }

This is interesting. But if I do that, in which way should I change my code to make it work? Sorry, but I don't get it.



43.9k

Please, could you explain why you are suggesting to comment that line?

because I thing that here you're manipulating a RobotsParentChild object (RobotsParentChild)

and you assing it the $my_id value here:

$robot_parent_child->id_parent_robot = $my_id;

so it looks to me that with both lines, it could be confusing for the framework ...



43.9k
edited Jan '18

// RobotsParentChild model
   public function initialize()
   {
       $this->setSchema("myschema");
       $this->setSource("robots_parent_child");
      // with both relations aliased as Robots, it's ambigous, and
      // each relation is belong_to one Robot (only) so I use no plurals here
       $this->belongsTo('id_parent_robot', '\Robots', 'xid', ['alias' => 'parentRobot']);
       $this->belongsTo('id_child_robot', '\Robots', 'xid', ['alias' => 'childRobot']);
   }

// Robots model
   public function initialize()
   {
       $this->setSchema("myschema");
       $this->setSource("robots");
      // each relation is has_many Robots so I use plurals here
       $this->hasMany('id_parent_robot', '\RobotsParentChild', 'xid', ['alias' => 'parentRobots']);
       $this->hasMany('id_child_robot', '\RobotsParentChild', 'xid', ['alias' => 'childRobots']);
   }

// code elsewhere

$robot = Robots::findFirstById($id);
$childs = $robots->childRobots; // these are RobotsParentChild obects
foreach ($childs as $child){
    echo $child->childRobot->name; // through the relation childRobot in RobotsParentChild you can acces to the Robots name property
}

$robots = RobotsParentChild::findByIdParentRobot($id_parent_robot); 
foreach ($robots as $robot){
    echo $robot->parentRobot->name;


13.8k

I mistakenly mark as answer an own comment, then deleted to try to mark as answer the last comment of @le51, but now I can't, it seems that Phosphorum have a bug here.



13.8k

This is the right answer, imo.


// RobotsParentChild model
  public function initialize()
  {
      $this->setSchema("myschema");
      $this->setSource("robots_parent_child");
     // with both relations aliased as Robots, it's ambigous, and
     // each relation is belong_to one Robot (only) so I use no plurals here
      $this->belongsTo('id_parent_robot', '\Robots', 'xid', ['alias' => 'parentRobot']);
      $this->belongsTo('id_child_robot', '\Robots', 'xid', ['alias' => 'childRobot']);
  }

// Robots model
  public function initialize()
  {
      $this->setSchema("myschema");
      $this->setSource("robots");
     // each relation is has_many Robots so I use plurals here
      $this->hasMany('id_parent_robot', '\RobotsParentChild', 'xid', ['alias' => 'parentRobots']);
      $this->hasMany('id_child_robot', '\RobotsParentChild', 'xid', ['alias' => 'childRobots']);
  }

// code elsewhere

$robot = Robots::findFirstById($id);
$childs = $robots->childRobots; // these are RobotsParentChild obects
foreach ($childs as $child){
  echo $child->childRobot->name; // through the relation childRobot in RobotsParentChild you can acces to the Robots name property
}

$robots = RobotsParentChild::findByIdParentRobot($id_parent_robot); 
foreach ($robots as $robot){
  echo $robot->parentRobot->name;


43.9k
edited Jan '18

$robot = ($id === null) ? new Robots() : Robots::findFirstById($id);
if ($id === null) {
  $robot_parent_child = new RobotsParentChild();
  $robot_parent_child->id_child_robot = $robot->id; // $robot is a new Robots object. so long that you haven't call $robot->save(), it doesn't hold any id
} else {
  $robot_parent_child = RobotsParentChild::findFirstById($id); // there is no id column in that model
  $robot_parent_child->id_child_robot = $id;  
}
$robot_parent_child->id_parent_robot = $my_id;
$robot->RobotsParentChild = $robot_parent_child;

if ($id === null) {
  $robot = new Robots();
  $childRobot[0] = new RobotsParentChild();
  $childRobot[0]->id_parent_robot = $my_id;
  $robot->childRobots = $childRobot; // while saving $robot, $childRobot should be filled with the correct id of the new robot object
} else {
  $robot = Robots::findFirstById($id);
  $childRobot = RobotsParentChild::findFirstByIdChildRobot($id);
  $childRobot->id_child_robot = $id;
  $childRobot->id_parent_robot = $my_id;
}

    if ($robot->save() === false) {
        $messages = $part->getMessages();

        foreach ($messages as $message) {
            echo $message;
        }

        break;
    }