Yii Framework Forum: Cform Not Submitting (Empty $_Post) - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Cform Not Submitting (Empty $_Post) Rate Topic: -----

#1 User is offline   MistaMoh 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 23-August 13

Posted 28 September 2013 - 01:07 AM

Hi there,

I am developping an admin interface in my yii app for managing translations.

I have defined the following Cform configuration array :

return array(

	'title'=>t('Form_Translations_Title'),

	'elements'=>array(),
	
	'buttons'=>array(
		'save'=>array(
			'type'=>'submit',
			'label'=>t('Form_Translations_Submit'),
		),
	),
);


And I populate it at runtime by browsing my sourceMessages DB table, and my available languages in my translatedMessages table.
This works since I am able to display the source messages and their translations in this Form_Translations_Title of mine.

The problem, is when i submit, the $_post var is empty.

Here's the action code :

$translationsForm = $this->controller->loadTranslationsForm();
		
		var_dump($_POST);
		
		// check if translationsForm submitted some source messages and / or translations and save them
		// note that there is no validation because the form doesn't have a model
		// no validation neither in the rows because the TranslationsRows instances are not ActiveRecords
		// this is why we enable validation in the save calls
		if($translationsForm->submitted('save'))
		{
			foreach($translationsForm->elements as $translationRow)
			{
				$translationRow['source']->model->save();
				
				foreach($translationRow['translations']->elements as $translation)
					$translation->model->save();
			}			
			$this->controller->redirect(array('translations'));
		}


I suspect that my issue is that I didn't define a model for the translationsForm. It doesn't seem relevant.

Also, here's the loadTranslationsForm() operations below.
Any ideas why i get a null post ?

If it's for the reason i'm suspecting, then i believe it's a bad behaviour from the submit logic, because I only want to populate models associated with subforms.

As you can see below, I already had to declare a useless model in my TranslationsRowForm to get the code working.
Maybe this could be part of the issue...


	public function loadTranslationsForm()
	{
		$translations = TranslationsRow::getTranslationsRows();
		if($translations===null)
			throw new CHttpException(404,'The requested page does not exist.');
		return new TranslationsGridForm($translations);
	}


/*
 * TranslationsGridForm is the CForm meant to update every source message and its translations in every target language.
 * For each sourceMessage, it includes a TranslationsRowForm element
 */
	 
class TranslationsGridForm extends GTForm
{
	private $_translations;
		
	public function __construct($translations)
	{
		parent::__construct('application.views.admin.forms.translationsGridForm');

		$this->_translations = TranslationsRow::getTranslationsRows();
		
		$this->model = $this->_translations[0];
		
		// create translationsRowForm for each available sourceMessage
		foreach($this->_translations as $translationsRow)
			$this[$translationsRow->sourceModel->id] = new TranslationsRowForm($translationsRow);
	
	}
	
}

class TranslationsRowForm extends GTForm
{
	public function __construct(/*TranslationsRow*/ $translationsRow)
	{
		parent::__construct('application.views.admin.forms.translationsRowForm');
		
		$this->model=$translationsRow;
		
		// Add source message element
		$this['source']=new CForm('application.views.admin.forms.translationsSourceMiniForm',$translationsRow->sourceModel);
		
		// Add translations elements for each supported language
		foreach($translationsRow->translationsModels as $translation)
		{
			$this['translations'][$translation->language] = new CForm('application.views.admin.forms.translationsTargetForm',$translation);
		}
	}
}



0

#2 User is offline   MistaMoh 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 23-August 13

Posted 30 September 2013 - 08:54 PM

First, I didn't print the _$POST at the right place. Nevermind that.

What I understood from further testing and diving into yii core code, is that you just can't use multiple instances of the same model in a Nested CForm.
That is because the name attribute of the fields will be duplicated (name of the model + name of the field).

I'm currently trying to change the name attribute. I'll let you informed.
0

#3 User is offline   MistaMoh 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 23-August 13

Posted 17 October 2013 - 04:11 PM

Right, easiest way is to override both element rendering and data loading methods.
Making extended use of these techniques on my app. $_POST and models are populated now.

If anyone needs samples, please let me know.
0

#4 User is offline   iredan 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 49
  • Joined: 11-September 13

Posted 24 October 2013 - 05:14 AM

View PostMistaMoh, on 17 October 2013 - 04:11 PM, said:

Right, easiest way is to override both element rendering and data loading methods.
Making extended use of these techniques on my app. $_POST and models are populated now.

If anyone needs samples, please let me know.


Hi I'm running into a similar issue as you. Would you be able to further describe how you fixed it?
Thanks
0

#5 User is offline   MistaMoh 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 23-August 13

Posted 24 October 2013 - 05:41 PM

View Postiredan, on 24 October 2013 - 05:14 AM, said:

Hi I'm running into a similar issue as you. Would you be able to further describe how you fixed it?
Thanks


Sure.
Below is how I handled the main issues one meets when using a CForm with multiple instances of a same model.

Note that it doesn't work natively in yii because the default generated html code will not differentiate your subforms fields between your different models.
Thus, when you submit, the post method will find different fields with exactly the same name, and it will succesively replace the data of the previous models. At the end, $_POST will only store the values of your last model. (hope this is clear, but the interesting part is next anyway)

1. If you need to populate the form at runtime, you have to make sure both Sons CForm->parent property as well as Parent CForm->elements property are properly initialized.
To do so, you'll have to create a CForm and specify the parent CForm (initializes 'parent'), and then explicitly attach the created CForm to its parent (initializes 'elements').

Sample :

// create DivisionClans' forms and fill with existing model
for ($i = 0;$i < $this->_clanCount; $i++)
{
	// Instanciate the DivisionClan Model, depending on create or update scenarios
	$clanModel = $i < count($this['division']->model->clans) ? 
		CompetitionsDivisionsClans::model()->findByPK(array('Division_ID'=>$this['division']->model->Division_ID, 'Clan_ID'=>$this['division']->model->clans[$i]->Clan_ID))
		: new CompetitionsDivisionsClans();
			
	// Instanciate Clan Form and add it as sub-form (setting parent in constructor isn't sufficient)
	$clanForm = new GTForm('application.views.management.forms.divisionClanForm',$clanModel,$this['clans']);
	$this['clans'][$i] = $clanForm;
			
}


2. Override the render method to make sure the models fields don't have the same name in the HTML output :

public /*overrides*/ function render()
{
	$output=$this->renderBegin();
		
	$output.="<legend>".$this->title."</legend>\n";
		

	// render season
	$output.=$this['division']->render();
		

	// render clans
	$output.="<legend>".$this['clans']->title."</legend>\n";
	
	
	foreach($this['clans']->elements as $i => $clanForm)
	{
		$output.="<fieldset>\n";
		$output.=strtr($clanForm['Clan_ID']->render(),array($clanForm['Clan_ID']->name=>"{$i}"));
		$output.="</fieldset>\n";
	}	
	
	// render button
	$output.=$this->buttons['save']->render();
	
	return $output . $this->renderEnd();	
}



3. Override the loadData method to make sure Yii fills the right models with the right $_POST elements :

public /*overrides*/ function loadData()
{
	$this['division']->loadData();
	
	for($i=0; $i<$this->_clanCount; $i++)
	{
		$this['clans'][$i]->model->Clan_ID=$_POST['CompetitionsDivisionsClans'][$i];
	}
}



This works and can be used for more complex scenarios. In my translations management scenario, each cell of the table is actually a subForm with its own model. In that more specific case, you just have to make your fields names bi-dimensional so that you get things like $_POST[sourceID][languageID].
Hope this helps. It can save days if it does.
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users