6

I am working with PhalconPHP and so far I have had little problems.

The framework is very good.

However, I've run into a problem that I haven't been able to sort out. It's probably a very simple thing but I've been running in circles, and couldn't find any reference to this problem.

The problem is I cannot update a model object if I also update a related entity.

For example, let's suppose I have a couple of model classes.

Contact:

class Contact extends \Phalcon\Mvc\Model
{
    public function initialize()
    {
        $this->belongsTo('email_id', 'Email', 'id', ['alias' => 'Email']);
    }
}

And Email:

class Email extends \Phalcon\Mvc\Model
{
    public function initialize()
    {
        $this->hasMany('id', 'Contact', 'email_id', ['alias' => 'Contacts']);
    }
}

When I try to create a new Contact and Email the following works:

$contact = new Contact();
// ... assign other fields here (i.e. name)
$email = new Email();
// ... assign other email fields here (i.e. address)
$contact->setEmail($email); // or $contact->email = $email;
$contact->save();
// record created

However, when I try to update a Contact and change the Email relation, the information is just not updated:

// Only update other fields
$contact->name = 'Some other name';
$contact->save();    // This works

// Update the related object
$contact->name = 'A new name';
$contact->setEmail($anotherValidEmail);
$contact->save();    // This doesn't work! Not even the name field is updated

I have tried using update() instead of save().

I have tried using $contact->email = $newEmailObject as well, but I get the same results.

Have anyone ran into this problem? What am I doing wrong?

I'm using Mac OS X, PhalconPHP 1.2.3

I've also tested it on Windows 8, with PhalconPHP 1.1.0

Any help is appreciated.

updated

I have printed the results of $contact->getMessages() after save(), but I get no results. It's as if save() was successful, however, no SQL statement is executed.

LAST UPDATE: Problem replicated and Workaround found!

We have been able to replicate the problem. We are doing this:

$contact = Contact::findFirst(123);
if ($contact->email->emailaddress != $newaddress) {
    $email = new Email();
    $email->emailaddress = $newaddress;

    $contact->email = $email;
    $contact->save();
}

This DOES NOT WORK! Once we compare the emailaddress field from the email related object, to the string for the new address saving does not work.

However, if we modify the code a little bit and do this:

  $contact = Contact::findFirst(123);
  if ($contact->email->emailaddress != $newaddress) {
    $email = new Email();
    $email->emailaddress = $newaddress;

    // Load the record (again!)
    $contact = Contact::findFirst(123);
    $contact->email = $email;
    $contact->save();
  }

This actually works.

I guess that loading the related object affects the ability to update that particular field, and finding the contact object again, flushes the related object.

So, we have a workaround that I hope will help other people facing the same problem.

TommyBs
  • 9,354
  • 4
  • 34
  • 65
hlasso
  • 389
  • 1
  • 3
  • 7
  • 1
    Maybe some validation messages were produced, try print_r($contact->getMessages()); after save() – twistedxtra Aug 21 '13 at 02:00
  • @twistedxtra, I did that already, but I get no errors at all. I'm also logging all SQL statements (via an EventsManager), but I'm getting no SQL statements at all for the Contact update. – hlasso Aug 21 '13 at 13:53
  • I modified the code, because I was only printing $contact->getMessages() when save() returned false. Now I'm always printing after save(), I still get the same results: no errors, nothing is saved, and no SQL statements executed. – hlasso Aug 22 '13 at 02:09
  • 1
    $contact->setEmail(...) only works if you have that method implemented in the model, can you try using public properties? – twistedxtra Aug 22 '13 at 14:26
  • Hi @twistedxtra, I will test using the magic property and will report back. I think I tested it before with the public property and it didn't work either, but I will test again. – hlasso Aug 23 '13 at 01:31
  • Have you found an answer for your question. I'm having the same problem – WooDzu Nov 12 '13 at 15:26
  • Hi @WooDzu, I haven't. I had to move along with my project and control changing this in other ways. I'll revisit this part of the project soon and probably will be able to dedicate more time to sort this out. – hlasso Nov 13 '13 at 19:16
  • We checked today on a co-worker's computer, and the code works. It seems to be a problem with my Mac OS X installation. – hlasso Nov 18 '13 at 23:25
  • Hi @WooDzu, we found today what may be the source of the problem... I updated the question with a description on how to replicate the issue, and a workaround. – hlasso Apr 04 '14 at 22:09
  • Thanks for the info, I will give it a go. Which version of Phalcon are you using btw? – WooDzu Apr 05 '14 at 10:18
  • Hi @WooDzu, we are using 1.2.6, although we also have a dev machine with 1.3.0. We have replicated the issue on the 1.2.6, we haven't tested it in the other machine – hlasso Apr 06 '14 at 01:20
  • does $contact->getMessages() return anything? – CodeMonkey Apr 08 '14 at 15:48
  • @CodeMonkey, no it doesn't and $contact->save() returns true – hlasso Apr 09 '14 at 18:38
  • I had a similar problem after deleting related records and then adding new ones. Had to load the record again as you did. Thanks (Phalcon 1.3.2) – Jorge Zapata Oct 16 '14 at 23:57
  • Answer is bellow. You are most probably missing the getter, as I did. – OKE Apr 15 '16 at 12:22

3 Answers3

1

When you use $contact->setEmail($anotherValidEmail);, you must have a set and get method in the Contact model Contact. For example:

Class Contact
{

  public $email;

  public function setEmail($email)
  {
  }
  public function getEmail()
  {
    return $this->email
  }
}
Ariel Allon
  • 862
  • 2
  • 10
  • 15
user2877596
  • 31
  • 1
  • 4
  • THIS! This is the answer. I had exactly same problem as the question was and then I realized I have no getter. This is really stupid and should be reported as bug or at least it should popup warning somwhere. – OKE Apr 15 '16 at 12:22
0

there is an answer in official doumentation, you should try it (add flag ACTION_CASCADE):

<?php

namespace Store\Models;

use Phalcon\Mvc\Model,
    Phalcon\Mvc\Model\Relation;

class Robots extends Model
{

    public $id;

    public $name;

    public function initialize()
    {
        $this->hasMany('id', 'Store\\Models\Parts', 'robots_id', array(
            'foreignKey' => array(
                'action' => Relation::ACTION_CASCADE
            )
        ));
    }

}

http://docs.phalconphp.com/en/latest/reference/models.html#cascade-restrict-actions

The above code set up to delete all the referenced records (parts) if the master record (robot) is deleted.

You can also use beforeDelete or afterDelete functions and add any code required:

http://phalcon-php-framework-documentation.readthedocs.org/en/latest/reference/models.html#deleting-records

all other available eventes: http://phalcon-php-framework-documentation.readthedocs.org/en/latest/reference/models.html#events-and-events-manager

Lukas Liesis
  • 24,652
  • 10
  • 111
  • 109
  • Hi Lukas, thank you for your reply. I'm not sure that this actually resolves the problem. The problem we had was not related to cascading deletes (removing referencing rows when their referenced rows are deleted). The problem is that we were changing the referenced row and it was not being updated. – hlasso Dec 02 '13 at 16:05
  • 'action' => Relation::ACTION_CASCADE - should do the trick, see the code in initialize() function, can you accept the answer if it helped? You can also add functions afterDelete or beforeDelete and add all required logic there. I've edited my answer, added links to these. – Lukas Liesis Mar 06 '14 at 09:00
  • Hi Lukas, that was not the issue. The problem updating was due to a faulty test equipment. After many tests we weren't able to replicate it. – hlasso Apr 01 '14 at 10:26
  • Hello, We have been able to replicate the problem, and we have found the source of the problem. I have modified the question to reflect this... – hlasso Apr 04 '14 at 21:59
0
Actually, your model should look like as below

class Contact extends \Phalcon\Mvc\Model
{

  public $id;
  public $name;
  public $email;

  public function initialize()
  {
     $this->belongsTo('email_id', 'Email', 'id', ['alias' => 'Email']);
  }

  public function columnMap()
  {
      return array(
        'id' => 'id', 
        'name' => 'name', 
        'email' => 'email'
      );
  }

}

Then,

$contact = new Contact();

$success = $contact->save($this->request->getPost(), array('name', 'email'));