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

Relations are not updating

I have an Article, which can have multiple:

  • categories (up to 3)
  • tags (no limits)

When I am creating an article all relations are saved correctly, but when I am trying to update article only main entity is updated, no relation is saved.

It should work from the start, but maybe I need some switch or additional settings e.g. action as following

    public function initialize()
    {
        $this->hasMany('id', __NAMESPACE__ . '\Categories2Articles', 'category_id', [
            'alias' => 'categories2articles',
            'foreignKey' => [
                'action' => Relation::ACTION_CASCADE,
                'message' => 'Category cannot be deleted because it\'s used on Categories2Articles'
            ]
        ]);
    }

I am saving an article in something like that:

$article = Articles::findFirstById($id);

// assign categories
$article->categories = $this->getCategoriesToInsert();

// assign tags
$article->tags = $this->getTagsToInsert();

where both functions getCategoriesToInsert() and $this->getTagsToInsert() return an array with new and existing records.

yours category alias is categories2articles then

$article->categories2articles = $this->getCategoriesToInsert();

Tip: the message in foreing key is to check the relation record exists. could be Category doesn't exists

Good luck

@emiliodeg Thank you for the anwser, but I am not sure if it is correct.

Here are my models:

An article

/**
 * Class Articles
 * Stores articles available on the website
 *
 * @package Website\Models
 */
class Articles extends Model
{
    // [...]

    /**
     * ID
     * @var integer
     */
    public $id;

    /**
     * Name
     * @var string
     */
    public $title;

    // [...]

    /**
     * Define relationships to Users and Permissions
     */
    public function initialize()
    {
        // Categories
        $this->hasMany('id', __NAMESPACE__ . '\Categories2Articles', 'article_id', [
            'alias' => 'categories2articles',
            'foreignKey' => [
                'message' => 'Article cannot be deleted because it\'s used on Categories2Articles'
            ]
        ]);
        $this->hasManyToMany(
            'id',
            __NAMESPACE__ . '\Categories2Articles',
            'article_id',
            'category_id',
            __NAMESPACE__ . '\Categories',
            'id'
        );

        // Tags
        $this->hasMany('id', __NAMESPACE__ . '\Tags2Articles', 'article_id', [
            'alias' => 'tags2articles',
            'foreignKey' => [
                'message' => 'Article cannot be deleted because it\'s used on Tags2Articles'
            ]
        ]);
        $this->hasManyToMany(
            'id',
            __NAMESPACE__ . '\Tags2Articles',
            'article_id',
            'tag_id',
            __NAMESPACE__ . '\Tags',
            'id', [
                'alias' => 'tags',
                'params' => [
                    'order' => 'name ASC',
//                    'conditions' => 'is_active = 1',
//                    'cache' => ['lifetime' => 3600, 'key' => 'current-active-post-tags']
                ]
            ]
        );
    }
}

An e.g. categories:

/**
 * Class Categories
 * Stores categories available on the website
 *
 * @package Website\Models
 */
class Categories extends Model
{
    /**
     * ID
     * @var integer
     */
    public $id;

    /**
     * Name
     * @var string
     */
    public $name;

    /**
     * Slug
     * @var string
     */
    public $slug;

    /**
     * Define relationships to Users and Permissions
     */
    public function initialize()
    {
        $this->hasMany('id', __NAMESPACE__ . '\Categories2Tutorials', 'category_id', [
            'alias' => 'categories2tutorials',
            'foreignKey' => [
                'action' => Relation::ACTION_CASCADE,
                'message' => 'Category cannot be deleted because it\'s used on Categories2Tutorials'
            ]
        ]);
    }
}

and model describing their relationship:

class Categories2Articles extends Model
{
    /**
     * ID
     * @var integer
     */
    public $id;

    /**
     * Name
     * @var string
     */
    public $category_id;

    /**
     * Slug
     * @var string
     */
    public $article_id;

    /**
     * Sets table name
     *
     * @return string
     */
    public function getSource(): string
    {
        return "categories2articles";
    }

    /**
     * Define relationships to Users and Permissions
     */
    public function initialize()
    {
        $this->belongsTo(
            'category_id',
            __NAMESPACE__ . '\Categories',
            'id', [
                'alias' => 'categories',
                'reusable' => true
            ]
        );

        $this->belongsTo(
            "article_id",
            __NAMESPACE__ . '\Articles',
            'id', [
                'alias' => 'articles',
                'reusable' => true
            ]
        );
    }
}

So, when I am inserting new article... relation aliases seem to work fine.

But, when I am updating existing article... relation aliases seem to not work at all.

I can try to insert Categories2Articles records, but why?

@emiliodeg is right, to access to a model's relation you need to use the alias.
https://olddocs.phalcon.io/en/3.0.0/reference/model-relationships.html#aliasing-relationships

$article = Articles::findFirstById($id);

// assign categories
$article->categories2articles = $this->getCategoriesToInsert();

// assign tags
$article->tags2articles = $this->getTagsToInsert();

@corentin-begne In my case I can successfully insert article with it's relationship:

// assign categories
$article->categories = $this->getCategoriesToInsert();

// assign tags
$article->tags = $this->getTagsToInsert();

If I understand both of you correctly, in the article update I need to set other objects:

  • Categories2Articles
  • and Tags2Articles.

Am I right?

Can ORM do it's magic for me in the update as it is work fine during article creation?

Should I remove old relationships first like:

$article->categories2articles->delete();
$article->categories2articles = $this->getCategoriesToUpdate();

And last thing. When I was assigning category relationship when I was inserting new article, list of categories (new and existing) was given to ORM. Do I need to make all things on my own during the article update?

don't remove all relations, only whats are gone, and add the new ones

edited Mar '18

I added new feature to my fork of Vokuro: https://github.com/phalcon/vokuro/pull/81/files#diff-8b4483a7080f4eb39cf26c28a55b614cR182

I added additional SQL file:

  • schemas/robot-parts-postgresql.sql

And RobotsController, where I added function processRobotParts($robot, $oldPartNames, $newPartNames), which finds 3 states of the relationship:

  • not changed,
  • to delete
  • to add

And it works nice.

Code may be tuned. It is just draft.

It bases on parts field, which stores parts as a string containg part names separated with comma.