The best way to do this? (Many-to-many)

Yup… I have another many-to-many related question… I feel like such a newbie asking so much, but hey… I guess we all gotta learn, eh?

So here's the thing… I have everything set up nicely, and it's working like a charm (and FAST! Yay!)… But now I need to find out how to best link Locations to Stores…

Here's how I picture it:

Since there's only a limited number of Stores available, I'm going to list them by type, and display them in a CTabView on either the create/update actions pages, or a separate action called addStores. So far so good… Each one should be represented by a checkbox, so the store's presence at the location can be enabled/disabled by checking or unchecking the box… (And saving of course)

But how do I do this best in Yii? I can think of doing it really manually, but then I’d have to bypass all the automation of Yii, and I’m sure there has to be a better way… So I hope someone will be able to help with this. :)

Where is the many-many relationship? And what is the problem you are trying to solve?

Sorry, I didn’t explain that well enough. :)

The two classes are Location and Store. I have the following relation defined in Location:

'stores' => array(self::MANY_MANY, 'Store', 'LocationStore(locationId, storeId)')

And of course another one in Store pointing to Location.

What I would like to do, step by step, is:

  • Load all stores. (Already doing this with Store::model()->findall())
  • Create a checkbox with accompanying label for each store, so that a checked checkbox can easily identify that a store exists at a specific location.
  • Handle the submitted data to create the links between the stores and the selected location.

Are the checkboxes initially unrelated with stores?

There's no automagic way to achieve this, but the following steps may simplify your work:

  1. You could define in your store model an attribute named locationInput which is an array indicating the location IDs that this store is at.

  2. In the view, you use activeCheckBoxList() to generate a checkbox list based on the "locationInput" attribute. The list data comes from a findAll() call of the location table.

  3. In your store model, you will need to override beforeSave() to insert links into StoreLocation table using the data in locationInput.

I’m not sure I’ve explained it right then. :)

My goal is to define which stores are at which locations. Initially the stores aren't in any of the locations… I would like to show all stores as checkboxes, and if the checkbox is then checked, and submitted, the store will be attached to that particular location.

Say we have the following stores:

  • Goodmans Store
  • Sec-Gen
  • Delgado Drones

And the locations:

  • Eden
  • George Town
  • Haven

So if I go in to the "addStores" (or whatever I decide to name that function) I would like it to show three checkboxes, one for each store, and the checked/unchecked status of it determines if the store exists at that location.

How do you display a store beside a location if they don't have relation yet?

The relation is shown by the status of the checkbox… So in the former case, say that Eden has Goodmans Store, George Town as Sec-Gen, and Haven has Sec-Gen and Delgado Drones… Here's how the addStores action would look in each case:


[X] Goodmans Store

[ ] Sec-Gen

[ ] Delgado Drones

George Town

[ ] Goodmans Store

[X] Sec-Gen

[ ] Delgado Drones


[ ] Goodmans Store

[X] Sec-Gen

[X] Delgado Drones

So basically… List all stores, showing them as checkboxes… If the store is connected to the location, it's checked, otherwise it's unchecked… When the user submits the form, the checkboxes that are checked determine which stores are connected to which locations.

I see. So my suggestion in http://www.yiiframew…36.html#msg5636 should still work, but in the other way around.

I hate to be a bother, but… Can I trouble you for a code example of this? I'm having trouble figuring out how you mean.


foreach($locations as $i=>$location)


    echo CHtml::activeCheckBoxList($location, "storeInput[$i]", 

           CHtml::listData($allStores, 'id', 'name'));


Then follow the instructions on the tabular form input tutorial page in the Guide.

But I'll only be editing one Location at the time. Anyway, I think you've given me enough that I can do it. Thank you.

You rock as much as your framework does. :) I hope you know that? :)

on this topic:

@qiang: I have a problem which could may be solved by your suggestion. could you explain where to fill the attribute "locationInput"?