MANY_MANY relation returns error in Yii 1.0.6

Hello,

Could anybody please tell me what's wrong with this:

I have a MANY_MANY relation (declared in MySQL with innoDB) but when I try to retrieve data from this relation, Yii returns errors.

Table Event

eventId (PK) - integer(6) unsigned

eventName

Table Artist

artistId (PK)  - integer(6) unsigned

artistName

Table Event_Artist

eventId  (PK)  - integer(6) unsigned references Event.eventId

artistId (PK)  - integer(6) unsigned references Artist.artistId

Model Event

public function relations()


{


	return array(


	  'artists'=>array(self::MANY_MANY,'Artist','Event_Artist(eventId,artistId)'),


	);


}

Model Artist

public function relations()


{


	return array(


	  'events'=>array(self::MANY_MANY,'Event','Event_Artist(eventId,artistId)'),


	);


}

Model Event_Artist

public function relations()


{


	return array(


	  'event'=>array(self::BELONGS_TO,'Event','eventId'),


	  'artist'=>array(self::BELONGS_TO,'Artist','artistID'),


	);


}

If I try to do the following in the EventController:

public function actionAdmin()


{


    ...





	$eventList=Event::model()->with('artists')->findAll();





	$this->render('admin',array(


		'eventList'=>$eventList,


		...


	));


}

Yii returns:

Invalid argument supplied for foreach()

Any other relations with Event model are ok. If I use the Event::model()->findAll() and then I try to write in the Event update view:

<?php $this->beginWidget('system.web.widgets.CClipWidget', array('id'=>'Artists'));

    $artists = $event->artists;

    $this->endWidget();

?>

I got the error:

Invalid argument supplied for foreach()

I need to retrieve all the artists related to the event and show them in a tab beside the event _form data. It's like:

|Event Data|      |Artists in Event|

renders Event_form      renders artists who have played in the event

I have related data in Event_Artist, Event and Artist tables…really can't see what's wrong…it seems like the MANY_MANY relation simply doesn't work for me.

Please, I need to solve this to release a project for my client, if somebody could help me I would appreciate so much!

Thanks,

Please provide more error information rather than just "Invalid argument supplied for foreach()".

Thanks Qiang, the first case error:

When I put in EventController;

public function actionAdmin()


{


	$this-&gt;processAdminCommand();





	$criteria=new CDbCriteria;

        $status = (is_numeric($_GET['status']))? (int)($_GET['status']) : 0;

        if($status > 0) {

            $criteria->condition='eventStatus=:status';

            $criteria->params=array(':status'=>$status);

        }

	$pages=new CPagination(Event::model()-&gt;count($criteria));


	$pages-&gt;pageSize=self::PAGE_SIZE;


	$pages-&gt;applyLimit($criteria);





	$sort=new CSort(&#039;Event&#039;);


	$sort-&gt;applyOrder($criteria);





	$eventList=Event::model()-&gt;with(&#039;artists&#039;)-&gt;findAll($criteria);





	$this-&gt;render(&#039;admin&#039;,array(


		&#039;eventList&#039;=&gt;$eventList,


		&#039;pages&#039;=&gt;$pages,


		&#039;sort&#039;=&gt;$sort,

            'status'=>$status,

	));


}

Without the with('artists'), it works great, but teh code above returns

Invalid argument supplied for foreach()

Source File

/var/www/yii/framework/db/ar/CActiveRecord.php(2150)

02138:                array('{class}'=>get_class($model),'{table}'=>$tableName)));

02139:        if($table->primaryKey===null)

02140:            $table->primaryKey=$model->primaryKey();

02141:        $this->tableSchema=$table;

02142:        $this->columns=$table->columns;

02143:

02144:        foreach($table->columns as $name=>$column)

02145:        {

02146:            if(!$column->isPrimaryKey && $column->defaultValue!==null)

02147:                $this->attributeDefaults[$name]=$column->defaultValue;

02148:        }

02149:

02150: foreach($model->relations() as $name=>$config)

02151:        {

02152:            if(isset($config[0],$config[1],$config[2]))  // relation class, AR class, FK

02153:                $this->relations[$name]=new $config0;

02154:            else

02155:                throw new CDbException(Yii::t('yii','Active record "{class}" has an invalid configuration for relation "{relation}". It must specify the relation type, the related active record class and the foreign key.',

02156:                    array('{class}'=>get_class($model),'{relation}'=>$name)));

02157:        }

02158:    }

02159:

02160:    /**

02161:      * @return array list of validators

02162:      */

Stack Trace

#0 /var/www/yii/framework/db/ar/CActiveRecord.php(634): CActiveRecordMetaData->__construct()

#1 /var/www/yii/framework/db/ar/CActiveFinder.php(253): model()

#2 /var/www/yii/framework/db/ar/CActiveFinder.php(288): CActiveFinder->buildJoinTree()

#3 /var/www/yii/framework/db/ar/CActiveFinder.php(54): CActiveFinder->buildJoinTree()

#4 /var/www/yii/framework/db/ar/CActiveRecord.php(1582): CActiveFinder->__construct()

#5 /var/www/backend/protected/controllers/EventController.php(152): Event->with()

#6 /var/www/yii/framework/web/actions/CInlineAction.php(32): EventController->actionAdmin()

#7 /var/www/yii/framework/web/CController.php(300): CInlineAction->run()

#8 /var/www/yii/framework/web/CController.php(278): EventController->runAction()

#9 /var/www/yii/framework/web/CController.php(257): EventController->runActionWithFilters()

#10 /var/www/yii/framework/web/CWebApplication.php(332): EventController->run()

#11 /var/www/yii/framework/web/CWebApplication.php(120): CWebApplication->runController()

#12 /var/www/yii/framework/base/CApplication.php(133): CWebApplication->processRequest()

#13 /var/www/backend/index.php(11): CWebApplication->run()

Thanks

The second one case, when I write

$eventList=Event::model()-&gt;findAll($criteria);

in the EventController, so I can see the Admin view for Event, but when I try to write in the Event update view:

<?php $this->beginWidget('system.web.widgets.CClipWidget', array('id'=>'Artistas Participantes'));

    $artists = $event->artists;

    $this->endWidget();

?>

Got the following:

Invalid argument supplied for foreach()

Source File

/var/www/yii/framework/db/ar/CActiveRecord.php(2150)

02138:                array('{class}'=>get_class($model),'{table}'=>$tableName)));

02139:        if($table->primaryKey===null)

02140:            $table->primaryKey=$model->primaryKey();

02141:        $this->tableSchema=$table;

02142:        $this->columns=$table->columns;

02143:

02144:        foreach($table->columns as $name=>$column)

02145:        {

02146:            if(!$column->isPrimaryKey && $column->defaultValue!==null)

02147:                $this->attributeDefaults[$name]=$column->defaultValue;

02148:        }

02149:

02150: foreach($model->relations() as $name=>$config)

02151:        {

02152:            if(isset($config[0],$config[1],$config[2]))  // relation class, AR class, FK

02153:                $this->relations[$name]=new $config0;

02154:            else

02155:                throw new CDbException(Yii::t('yii','Active record "{class}" has an invalid configuration for relation "{relation}". It must specify the relation type, the related active record class and the foreign key.',

02156:                    array('{class}'=>get_class($model),'{relation}'=>$name)));

02157:        }

02158:    }

02159:

02160:    /**

02161:      * @return array list of validators

02162:      */

Stack Trace

#0 /var/www/yii/framework/db/ar/CActiveRecord.php(634): CActiveRecordMetaData->__construct()

#1 /var/www/yii/framework/db/ar/CActiveFinder.php(253): model()

#2 /var/www/yii/framework/db/ar/CActiveFinder.php(54): CActiveFinder->buildJoinTree()

#3 /var/www/yii/framework/db/ar/CActiveRecord.php(542): CActiveFinder->__construct()

#4 /var/www/yii/framework/db/ar/CActiveRecord.php(416): Event->getRelated()

#5 /var/www/backend/protected/views/event/update.php(37): Event->__get()

#6 /var/www/yii/framework/web/CBaseController.php(119): require()

#7 /var/www/yii/framework/web/CBaseController.php(88): EventController->renderInternal()

#8 /var/www/yii/framework/web/CController.php(701): EventController->renderFile()

#9 /var/www/yii/framework/web/CController.php(640): EventController->renderPartial()

#10 /var/www/backend/protected/controllers/EventController.php(81): EventController->render()

#11 /var/www/yii/framework/web/actions/CInlineAction.php(32): EventController->actionUpdate()

#12 /var/www/yii/framework/web/CController.php(300): CInlineAction->run()

#13 /var/www/yii/framework/web/CController.php(278): EventController->runAction()

#14 /var/www/yii/framework/web/CController.php(257): EventController->runActionWithFilters()

#15 /var/www/yii/framework/web/CWebApplication.php(332): EventController->run()

#16 /var/www/yii/framework/web/CWebApplication.php(120): CWebApplication->runController()

#17 /var/www/yii/framework/base/CApplication.php(133): CWebApplication->processRequest()

#18 /var/www/backend/index.php(11): CWebApplication->run()

Thanks again!!

:)

Have you tried doing a dump/trace on $event and $event->artist? It looks like $event->artist should be an array. I'd make sure that $event->artist is actually getting the data you want before sending it to the widget. That should make it easier to narrow down the problem. Also, I'm assuming you are getting $event by iterating over the $eventList array?

Check your model classes' relations() declaration. One of them is not defined correctly (it should return an array).

Qiang and Boston, thank you guys very much…it was solved by deleting all models/views for Event and Artist and creating them again with the yiic 1.0.6 version.

So, what I did in the Event update view:

<?php

if(isset($_GET['activeTab']))

{

    $activeTab = $_GET['activeTab'];

}

?>

<?php $this->beginWidget('system.web.widgets.CClipWidget', array('id'=>'Event Data')); ?>

<h2>Update Event <?php echo $model->eventId; ?></h2>

<div class="actionBar">

[<?php echo CHtml::link('List',array('list')); ?>]

[<?php echo CHtml::link('Manage',array('admin')); ?>]

[<?php echo CHtml::link('New',array('create')); ?>]

</div>

<?php echo $this->renderPartial('_form', array(

&#039;model&#039;=&gt;$model,


&#039;update&#039;=&gt;true,

    'activeTab'=>'tab1',

));

?>

<?php $this->endWidget(); ?>

<?php $this->beginWidget('system.web.widgets.CClipWidget', array('id'=>'Artists in Event')); ?>

<table class="dataGrid">

  <tr>

    <th><?php Artist Name ?></th>

&lt;th&gt;Actions&lt;/th&gt;

  </tr>

<?php

$artists = $model->artists;

foreach($artists as $n=>$artist): ?>

  <tr class="<?php echo $n%2?'even':'odd';?>">

    <td><?php echo CHtml::encode($artist->artistName); ?></td>

    <td>

<?php

echo CHtml::linkButton('Remove',array(

        'submit'=>$this->createURL('removeArtist'),

        'params'=>array('eid'=>$model->eventId,'aid'=>$artist->artistId,'activeTab'=>'tab2','which'=>$_GET['which'],'status'=>$_GET['status']),

        'confirm'=>"Sure?"));

?>

&lt;/td&gt;

  </tr>

<?php endforeach; ?>

</table>

<?php $this->endWidget(); ?>

<?php

$tabParameters = array();

foreach($this->clips as $key=>$clip)

    $tabParameters['tab'.(count($tabParameters)+1)] = array('title'=>$key, 'content'=>$clip, 'id'=>'tab'.(count($tabParameters)+1));

?>

<?php $this->widget('system.web.widgets.CTabView', array('tabs'=>$tabParameters,'activeTab'=>$activeTab)); ?>

It works smoothly fine now…when I click the Update link in Event Admin page, two tabs are opened: in the 1st one, I have the Event data, in the 2nd one I have the artists who have played in the Event. If I want to remove the artist from the list, I clik Remove and the system deletes the correct Event_Artist and reloads the Event update view in the 2nd tab!!!

Just what I needed!

Thank you guys very very much for your patience…

cheers!!!  :D