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

Updating data in a many-to-many relationship

Hello!

I have the following 3 tables:

  • Banner - Contains banners
  • Country - Contains a list of all countries
  • BannerCountry - Relationship between the two, defining where a certain banner can be displayed.

The models are defined as follows:

Banner:

class Banner extends Phalcon\Mvc\Model {

    public function initialize() {

        $this->hasManyToMany(
            'id',
            'BannerCountry',
            'bannerId', 'countryId',
            'Country',
            'id',
            ['alias' => 'countries']
        );
    }
}

Country:

class Country extends Phalcon\Mvc\Model {

    public function initialize() {

        $this->hasManyToMany(
            'id',
            'BannerCountry',
            'countryId', 'bannerId',
            'Banner',
            'id'
        );
    }
}

I've created a form which has all countries listed in a <select multiple> to allow changes of connected countries. However, whatever I do, I can't get the changes to save.

The code which does the save is basically this:

$banner = Banner::findFirst($bannerId);
$countries = Country::find('id IN (' . implode(',', array_values($this->request->getPost('countries'))) . ')');
$banner->countries = $countries;
$banner->save();

The last line returns TRUE every time but these changes are not saved in the database. Googling around and going through the documentation doesn’t tell me why won’t this work. By this post here it should all work normally: https://forum.phalcon.io/discussion/598/insert-new-data-with-manytomany-relationship



4.9k

I ended up making a workaround within the Banner model:

public function setCountryIds ($countryIds) {

    $this->bannerCountry->delete();

    foreach ($countryIds as $countryId) {
        $newBC = new BannerCountry();
        $newBC->bannerId = $this->id;
        $newBC->countryId = $countryId;
        $newBC->save();
    }

    $this->countries = $this->getCountries();

}

So setting new related countries is as simple as:

$banner->setCountryIds($this->request->getPost('countries'));

However, the form would not reflect the changes upon first reload after changes were made, so I had to make this workaround in the Banner Form object itself:

if ($this->request->hasPost('countries')) {
    $countries->setDefault($this->request->getPost('countries'));
} else {
    $countries->setDefault($banner->getCountryIds());
}

I was hoping for a more Phalcon-ish solution to this, but couldn't find one.