Getting data for 2 different models - Yii2 - php

I have a form that inside looks like that:
<?= $form->field($model, 'comment')->textarea(['rows' => 6]) ?>
<?= $form->field($presentation, 'attendance')->textInput(['maxlength' => true]) ?>
<?= $form->field($presentation, 'couples')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'hire_price')->textInput(['maxlength' => true]) ?>
Then I collect received data with controller, like that:
$model = new PresentationPlaceHistory();
$presentation = new Presentations();
if ($model->load(Yii::$app->request->post()) && $model->save() && $presentation->load(Yii::$app->request->post())) {
$pres = $presentation->findOne($model->presentation_id);
$pres->attendance = $presentation->load(Yii::$app->request->post('attendance'));
$pres->couples = $presentation->load(Yii::$app->request->post('couples'));
$pres->save();
return $this->redirect(['view', 'id' => $model->id]);
}
else {
return $this->render('create', [
'model' => $model,
'presentation' => $presentation,
]);
}
But in the effect, it saves all, beside 'attendance' and 'couples', which are set to 0 (before this form they were null).
It doesn't matter what number I put, I get zero. It doesn't even have to be number, because validation doesn't work at all.

Change following two lines:
$pres->attendance = $presentation->load(Yii::$app->request->post('attendance'));
$pres->couples = $presentation->load(Yii::$app->request->post('couples'));
// to this
$pres->attendance = $presentation->attendance;
$pres->couples = $presentation->couples;
You have already loaded $presentation values here $presentation->load(Yii::$app->request->post()) and should be available to access directly.

Kinda messy code u got here. First of all, I suggest you not to use load() method, but its my personal preference. Read more about load.
This method returns boolean, that is why you are getting 0 in model properties. In general, your code should look more like:
$model->load(Yii::$app->request->post());
if ($model->save()) {
$pres = $presentation->findOne($model->presentation_id);
$pres->attendance = $presentation->attendance;
//etc ...
$pres->save()
}
I dont know what is the point of your code, but this looks kinda pointless. Try to work with attributes, it is an array of all model properties. Or assign manually wanted properties of the model.

problem with your controller code, change following two lines
if ($model->load(Yii::$app->request->post()) && $model->save() && $presentation->load(Yii::$app->request->post())) {
$post_data= Yii::$app->request->post();
$pres = $presentation->findOne($model->presentation_id);
/* change these two lines */
$pres->attendance = $post_data['Presentations']['attendance'];
$pres->couples =$post_data['Presentations']['couples'];
/* change these two lines */
$pres->save();
return $this->redirect(['view', 'id' => $model->id]);
}
else
{
return $this->render('create', [
'model' => $model,
'presentation' => $presentation,
]);
}

Related

Value not updated in databases after validation and save success

Hi everyone i'm having trouble with my software developed with yii2.
I Have a model called Anagrafica and with its primary key id. With this model everything works.
I also have a model called AnagraficaOpzioniCarriera which extend the first one.
I have a view anagrafica/index that show a Kartik grid with the data of people enrolled that you can find in anagrafica. Admin user can update the data of an Anagrafica model by clicking on an the attribute "cognome" that render to anagrafica/update.
this is the command that call the controller AnagraficaController to reach anagrafica/update
'cognome'=>Grid::Labels('cognome',['anagrafica/update'],\app\helpers\Permits::allow('anagrafica','update'),'id','btn','info','10%'),
This is AnagraficaController
public function actionUpdate($id,$error=0,$message='')
{
$id = (int)$id;
$model = Anagrafica::findOne(['id' => $id]);
$model->scenario = 'update';
if ($model->load(Yii::$app->request->post())) {
if($model->validate()){
}
if($model->save(false)){
return $this->redirect(['anagrafica/update','id'=>$model->id]);
}
}
}
return $this->render('update', ['model' => $model, 'extended'=>true]);
}
i removed some portions of code to semplify it, but this is the core.
One time the view anagrafica/update is reached in this page i have an ActiveForm to modify data of the model and i have a render to a grid that show the attributes contained in AnagraficaOpzioniCarriera about the $model that i'm updating.
<?= $this->render('_opzioni_carriera',['parent'=>$model]); ?>
anagrafica/_opzioni_carriera view contain a Kartik grid that shows the column in the model AnagraficaOpzioniCarriera
<?php
use kartik\grid\GridView;
use kartik\select2\Select2;
use kartik\widgets\ActiveForm;
use kartik\editable\Editable;
use kartik\widgets\SwitchInput;
use yii\helpers\ArrayHelper;
use app\helpers\Autoconfigurazione;
use app\models\AnagraficaOpzioniCarriera;
use app\helpers\Grid;
use yii\helpers\Html;
use app\helpers\UserInfo;
/* #var $this yii\web\View */
/* #var $model app\models\AnagraficaOpzioniCarriera*/
$model = new AnagraficaOpzioniCarriera(['scenario'=>'search']);
?>
<div class="">
<?php
echo GridView::widget([
'options'=>[
'id'=>'opzioni_carriera',
],
'dataProvider'=> $model->search($parent->id,Yii::$app->request->queryParams),
'showPageSummary'=>false,
'headerRowOptions'=>['class'=>'kartik-sheet-style'],
'pjax'=>true, // pjax is set to always true for this demo
'pjaxSettings'=>[
'neverTimeout'=>true,
],
'toolbar'=> [
[
'content'=>''
],
],
'panel'=>[
'heading'=>false,
'footer'=>false,
'after'=>false,
],
'columns' => Grid::gridColumns([
'model'=>$model,
'checkbox'=>false,
'remove'=>Grid::gridRemove($model),
'extraOptions' =>[
'cashback' =>Grid::YNColumn('cashback',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'compensa'=>Grid::YNColumn('compensa',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'associazione'=>Grid::YNColumn('associazione',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'formazione'=>Grid::YNColumn('formazione',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
],
]);
?>
</div>
cashback, compensa etc.. are the attributes in the model AnagraficaOpzioniCarriera.
Here when i try to update this attributes everything looks fine, the function model->validate() and model->load returns true value, but at the end of the process doesn't works.
Honestly i don't know what i have to return from the function of the controller.
public function actionUpdate($id)
{
$model = AnagraficaOpzioniCarriera::findOne(['id_anagrafica' => $id]);
if (!$model) {
// Se l'anagrafica opzioni carriera non esiste, genera un'eccezione 404
throw new \yii\web\NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
}
$model->scenario = 'update';
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if(Yii::$app->request->post('cashback') != null) $model->cashback = Yii::$app->request->post('cashback');
if(Yii::$app->request->post('compensa') != null) $model->cashback = Yii::$app->request->post('compensa');
if(Yii::$app->request->post('associazione') != null) $model->cashback = Yii::$app->request->post('associazione');
if(Yii::$app->request->post('formazione') != null) $model->cashback = Yii::$app->request->post('formazione');
if ($model->save()) {
return Json::encode(["success" => true, 'message' => 'Dati aggiornati']);
}
}
// Mostra il form di modifica
return $this->render('_opzioni_carriera', [
'parent' => $model,
]);
}
anyone can help me? i hope i explained my problem in a good form, but my english is not the best, i know. Anyway thanks in aadvance to everyone who want to try to help me, if you need anything other you can easily ask.
I tried every everything, also a logger but nothing worked
Like someone suggest these are the rules of the model AnagraficaOpzioni, but like i said prevously model->validate() works, for this reason i think the problem is not over there
public function rules()
{
return [
[['id_anagrafica'], 'required'],
[['id_anagrafica'], 'integer'],
[['cashback', 'compensa', 'associazione', 'formazione'], 'required', 'on'=>['update']],
[['cashback', 'compensa', 'associazione', 'formazione'], 'integer'],
[['id_anagrafica', 'cashback', 'compensa', 'associazione', 'formazione',], 'safe', 'on'=>['search']],
];
}

Yii2: Trying to generate a csv file with ajax

Im trying to generate a basic csv file with some data. When I use an alert inside the ajax call it will show me the data(so there is data passing), but when I click the button it will not generate an CSV file. Im new to yii2 so im still learning.
UPDATED
I have changed the files
//view export/index.php
Pjax::begin();
$form = ActiveForm::begin([
'action' => yii\helpers\Url::to(['cms-export/index']),
'options' => ['data' => ['pjax' => true]],
'layout' => 'horizontal',
'fieldConfig' => [
'horizontalCssClasses' => [
'label' => 'col-sm-2',
'offset' => 'col-sm-offset-2',
'wrapper' => 'col-sm-5',
'hint' => 'col-sm-5',
],
],
]);
echo $form->field($model, 'language')->dropDownList([//some list]);
echo $form->field($model, 'filename')->textInput()
echo Html::submitButton('Submit', ['class' => 'btn btn-primary'])';
ActiveForm::end();
Pjax::end();
//model
public function generateCsv(){
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="sample.csv"');
$data = [datacomeshere];
$fp = fopen('php://output', 'w');
foreach ( $data as $line ) {
fputcsv($fp, $line, ';');
}
fclose($fp);
}
//controller
public function actionIndex()
{
$model = new Export();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
// validation works, but method does not work
\common\models\Export::generateCsv();
}
return $this->render('index' , ['model' => $model]);
}
When I click the button it will show me an 500 error in the jquery file
xhr.send( options.hasContent && options.data || null );
I would suggest the following approach, removing the whole JS code:
Make the link a real one. It makes sense to have a GET request, since you just getting data with the call.
<div class="modal-button-row">
Export
</div>
Modify the action now (probably in CmsExportController) and use the Yii download capability:
public function actionDownload() {
$csv = Export::generateCsvSomehow(); // this should return a csv string
return \Yii::$app->response->sendContentAsFile($csv, 'sample.csv', [
'mimeType' => 'application/csv',
'inline' => false
]);
}
More infos in guide: here.
You also need to remove Pjax, since it will do its own stuff with links and forms via JS! Or you have to configure Pjax, e.g. with $formSelector, which goes beyond the scope of this question.
One problem is definitely that the regular action call always creates headers, cookies and some content (even an empty string, e.g. if you have forgotten the return statement with $this->render(...)) that gets sent to the browser. I supsect that you get some Headers already sent error. So this has to be suppressed so that your CSV code takes control.
Try the following:
public function actionIndex() {
$model = new Export();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
\common\models\Export::generateCsv();
Yii::$app->response->isSent = true;
} else {
return $this->render('index' , ['model' => $model]);
}
}
Btw: Use method: GET in your form if no data gets changed with that call. This is a HTTP standard. POST is used when something gets added or changed.
However, I would recommend my other approach using Response::sendContentAsFile(). This should work with your ActiveForm as well. As noted in that answer you have to remove or configure Pjax.

I already asked , but how to access view page without id value in the url

my view.php
<?php
echo
Html::beginForm(['contactpersons/update'], 'post',['id' => 'update-form']) .
'<input type="hidden" name="id" value="'.$model->id.'">
<a href="javascript:{}" onclick="document.getElementById(\'update-form\').submit();
return false;">Update</a>'.
Html::endForm();
?>
<?= Html::a('Delete', ['delete', 'id' => $model->id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => 'Are you sure you want to delete this item?',
'method' => 'post',
],
])
?>
my controller is
public function actionView($id)
{
$model = $this->findModel($id);
return $this->render('view', ['model' => $model]);
}
How to modify this for getting my view page without id value in the url.
Thanks in advance.
You could change it like this
public function actionView($id = null) {
$model = null;
if ($id !== null) {
$model = $this->findModel($id);
}
return $this->render('view', ['model' => $model]);
}
However in your view you execute the following code: $model->id
this won't work when the model isn't set yo anything. So you could create a new model ($model = new ModelClass()) when the $id is null.
Sidenote: this doesn't look like an view action but more like an edit action, so maybe change your action to actionEdit().
You can send data to your browser by two methods - POST and GET. So, if you want to hide id parameter, then you need to send your id as POST parameter, which is bad solution - it's hard to implement, because POST is usally sends when you submit a form.

Yii2 multiple models in one form

How to use multiple models in one form in Yii2?
My case:
In my create action I can save into agenda_fiscalizacao table, but in update I receive this error when I try to load the form:
Call to a member function formName() on array
My Update Action:
public function actionUpdate($id)
{
$model = $this->findModel($id);
$modelAgenda = AgendaFiscalizacao::findAll(['fiscalizacao_id' => $id]);
if ($model->load(Yii::$app->request->post()) && Model::loadMultiple($modelAgenda, Yii::$app->request->post())) {
$valid = $model->validate();
$valid = $modelAgenda->validade() && $valid;
if ($valid) {
$model->save(false);
$modelAgenda->save(false);
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('update', [
'model' => $model,
'modelAgenda' => $modelAgenda
]);
}
My form view
<?= $form->field($modelAgenda, 'agenda_id')->checkboxList(Agenda::combo(), ['class' => 'checkbox']) ?>
<?= $form->field($model, 'bioma_id')->dropDownList(Bioma::combo(), ['prompt' => $prompt]) ?>
<?= $form->field($model, 'nome')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'tipo_doc')->radioList(['CPF'=>'CPF', 'CNPJ'=>'CNPJ'], ['class' => 'radio']) ?>
<?= $form->field($model, 'n_doc')->widget(MaskedInput::className(), ['mask' => ['999.999.999-99', '99.999.999/9999-99']]) ?>
<?= $form->field($model, 'observacao')->textarea(['rows' => 7]) ?>
What could be wrong?
EDIT (full error):
1) If you mean working with multiple models of the same type, the error is in this line:
$valid = $modelAgenda->validade() && $valid;
First, it should be $modelAgenda->validate(), second $modelAgenda contains array of models, validate() method can be called only on single model.
For validating multiple models Yii2 suggests using built-in method validateMultiple():
use yii\base\Model;
...
$valid = Model::validateMultiple($modelAgenda) && $valid;
Working with multiple models is well covered in official docs (Collecting Tabular Input).
Note that they recommend to index models array by id before like this:
$models = YourModel::find()->index('id')->all();
2) If you need just two models of different type, don't use findAll() because it's for finding multiple models and always returns array (even on empty result). Use new for create action and findOne() for update action to initialize models. Let's say you initialized two models, $firstModel and $secondModel, then you can load and save them like this:
$isSuccess = false;
Yii::$app->db->transaction(function () use ($isSuccess) {
$areLoaded = $firstModel->load(Yii::$app->request->post()) && $secondModel->load(Yii::$app->request->post();
$areSaved = $firstModel->save() && $secondModel->save();
$isSuccess = $areLoaded && $areSaved;
});
if ($isSuccess) {
return $this->redirect(['view', 'id' => $model->id]);
}
Transaction is added in case of saving of second model will fail (so the first model also will not be saved).
Alternatively, you can declare transactions inside your model, for example:
return [
'admin' => self::OP_INSERT,
'api' => self::OP_INSERT | self::OP_UPDATE | self::OP_DELETE,
// the above is equivalent to the following:
// 'api' => self::OP_ALL,
];
Then just use:
$firstModel->scenario = 'scenarioForTransaction';
$secondModel->scenario = 'scenarioForTransaction';
$areLoaded = $firstModel->load(Yii::$app->request->post()) && $secondModel->load(Yii::$app->request->post();
$areSaved = $firstModel->save() && $secondModel->save();
if ($areLoaded && $areSaved) {
return $this->redirect(['view', 'id' => $model->id]);
}
For more than two models, it's better to use loops.
P.S. I'd recommend to separate saving to different controllers / actions and call it via AJAX, it will be more user friendly.
For saving relations read - Saving Relations.
public function actionUpdate($id)
{
$model = $this->findModel($id);
$modelAgenda = AgendaFiscalizacao::findAll(['fiscalizacao_id' => $id]);
if ($model->load(Yii::$app->request->post()) && $modelAgenda->load(Yii::$app->request->post()) && Model::validateMultiple([$model, $modelAgenda])) {
$model->save(false);
$modelAgenda->save(false);
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('update', [
'model' => $model,
'modelAgenda' => $modelAgenda
]);
}
You can refer following link for example : http://blog.dedikisme.com/blog/2014/10/13/yii2-building-a-single-form-with-multiple-models
You are not rendering $modelAgenda from view/update.php to view/_form.php file while using render in update file.

Yii dropdownlist using $form-> dropdownlist

i want to create a form from 2 different models,
1st is for countries, and the 2nd is for documents.
The problem is that i can't make a dropdown list, i get the errors all the time.
Here's the code, first my controller.php part
$model = new Country;
$model2 = new Product;
$this->performAjaxValidation(array($model, $model2));
if(isset($_POST['Country'],$_POST['Product']))
{
// populate input data to $model and $model2
$model->attributes=$_POST['Country'];
$model2->attributes=$_POST['Product'];
// validate BOTH $model and $model2
$valid=$model->validate();
$valid=$model2->validate() && $valid;
if($valid)
{
// use false parameter to disable validation
$model->save(false);
$model2->save(false);
$this->redirect('index');
}
}
...
$countriesIssued = Country::model()->findAll(array('select'=>'code, name', 'order'=>'name'));
...
$this->render('legalisation', array('model'=>$model, 'model2'=>$model2, 'documents'=>$documents, 'countriesIssued'=>$countriesIssued, 'countries'=>$countries, 'flag'=>$flag));
}
In my view script I use this code
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'user-form',
'enableAjaxValidation'=>true,
)); ?>
<?php echo $form->errorSummary(array($model,$model2)); ?>
<?php echo $form->dropDownList($model, 'countriesIssued',
CHtml::listData($countriesIssued, 'code', 'name'));?>
<?php $this->endWidget(); ?>
but i get this error :
Property "Country.countriesIssued" is not defined.
Ok it's not defined, i try to change it to 'countriesIssued', then i got another error saying Invalid argument supplied for foreach() .
If anybody can help me please.
I know there is more solutions on net, i try it but not understand, Thanks.
By definition, the first param of listData is an array; Your is a object;
<?php
echo $form->dropDownList($model, 'classification_levels_id', CHtml::listData(ClassificationLevels::model()->findAll(), 'id', 'name'),$classification_levels_options);
?>
Make a list variable like this:
In your Model:
$countriesIssued = Country::model()->findAll(array('select'=>'code, name', 'order'=>'name'));
And in your view:
$list = CHtml::listData($countriesIssued, 'code', 'name'));
echo CHtml::dropDownList('Your variable', Your $model,
$list,
array('empty' => '(Select a category'));
dropDownList($model,'state',array('1' => 'Do 1', '2' => 'Do 2'),array('selected' => 'Choose')); ?>
Or Yii 2
field($model,'state')->dropDownList(
array('1' => 'Do 1','0' => 'Do 2'),array('options' => array('0' => array('selected' => true))))
->label('State')
?>

Categories