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

Many to Many Relation save process tries to update existing record nodes

Hello,

I have these objects model in my app:

Users Model:
namespace Application\Model;

class Users extends Entity
{
    public $id;
    public $firstName;
    public $lastName;
    public $gender;

    public function initialize()
    {
        parent::initialize();

        /* Created course by user (Course owner) */
        $this->hasMany('id', 'Application\Model\Courses', 'createdBy', array(
            'alias' => 'createdCourses',
            'foreignKey' => array(
                'message' => 'User cannot be deleted because he/she is courses owner in the system'
            )
        ));

        /* Teaching course by user */
        $this->hasManyToMany(
            'id',
            'Application\Model\Instructors',
            'userId', 'courseId',
            'Application\Model\Courses',
            'id',
            array(
                'alias' => 'teachingCourses',
                'foreignKey' => array(
                    'message' => 'User cannot be deleted because he/she has teaching courses in the system'
            )
        ));
    }
}
Courses Model:
namespace Application\Model;

class Courses extends Entity
{

    public $id;
    public $title;
    public $createdBy;

    public function initialize()
    {
        parent::initialize();

        /* Course creator (Owner) */
        $this->belongsTo('id', 'Application\Model\Users', 'createdBy', array(
            'alias' => 'creator'
        ));

        /* Course Instructors (Teachers) */
        $this->hasManyToMany(
            'id',
            'Application\Model\Instructors',
            'courseId', 'userId',
            'Application\Model\Users',
            'id',
            array(
                'alias' => 'instructors'
            )
        );
    }
}
Instructors Model:
namespace Application\Model;

class Instructors extends Base
{
    /**
     *
     * @var integer
     */
    public $id;

    /**
     *
     * @var integer
     */
    public $userId;

    /**
     *
     * @var integer
     */
    public $courseId;

    public function initialize()
    {
        parent::initialize();

        $this->belongsTo("userId", 'Application\Model\Users', "id");
        $this->belongsTo("courseId", 'Application\Model\Courses', "id");
    }
} 

In my controller I have create a course then select an existing user from database and assing as course instructor via magic method:


$course = new \Application\Model\Courses();
$course->title = "Sample Title";
.
.
$user = Application\Model\User::findFirst(1);
$course->createdBy = $user->id;
$course->instructors = [$user];
$course->save();

But while saving process, it tries to update that existing user to! Can someone explain what is wrong here.

Thanks.

It's updating the user because it has a hasManyToMany relation (that's ActiveRecord), use dynamic update within user model to avoid updating if no changes were made, see this thread https://forum.phalcon.io/discussion/6678/how-to-disable-saving-related-records

Thank you @Óscar for our quick reply.

I try this, but result is same... and related user updates !

 public function initialize()
 {
   parent::initialize();   
   $this->useDynamicUpdate(true);

   $this->hasManyToMany(
            'id',
            'Application\Model\Instructors',
            'userId', 'courseId',
            'Application\Model\Courses',
            'id',
            array(
                'alias' => 'teachingCourses',
                'foreignKey' => array(
                    'action' => \Phalcon\Mvc\Model\Relation::NO_ACTION,
                    'message' => 'User cannot be deleted because he/she has teaching courses in the system'
            )
        ));
 }

PS: My all models have Timestampable Behavior with createdAt and modifiedAt fields.

User's modifiedAt field allways updates in this situation!!

Thanks again.

Try using beforeUpdate instead

public function beforeUpdate() {
    if ($this->hasChanged()) {
        $this->modifiedAt = $_SERVER['REQUEST_TIME']; // or whatever date format you have
    }
}

So, do you mean I should do such thinng (hooking beforeUpdate) for all hasManyToMany models and forget about Timstampable behaviors?

Basicaly why update function of user model should be call in many to many save process when my model fields does not changes any more?

This smells bad an anti-dry code, does nt it?

So, What about saving relations manually and use defined relations for read and fetch action?

Is it normal or not?

Thank you again for your valuable replies Oscar. On 21 May 2015 22:22, "Óscar Enríquez" [email protected] wrote:

Yes, because 'Timestampable' behavior updates the property without checking if model changed, and thus cause the model change https://github.com/phalcon/cphalcon/blob/c0fd010390c8dd9a31f50915134b4c5d62db3aa6/phalcon/mvc/model/behavior/timestampable.zep#L89, I think thats good in this way, but implementing an option dynamicUpdate on it would be better.

And yes, Phalcon\Mvc\Model has some spaghetti code, about saving relations manually don't think that's a good idea, you will go better using another ORM if Phalcon does not meet your needs