I have a problem when it comes to saving the fields of tables being displayed three times. Cant save the unique value being saved in the text fields. Kindly someone direct me to the right answer please.
View code :
<h2>List of Documents</h2>
<table class="table">
<?php foreach($formlist as $item) { ?>
<tr>
<td><?= $form->field($model, '['.$item->id.']value')->radioList(['yes'=>' yes','no'=>' no'])->label($item['title']); ?></td>
</tr>
<?php } ?>
</table>
Controller code :
public function actionCreate()
{
$model = new Form();
$forminfo = new Forminfo();
$forminfo->id = $model->forminfo_id;
/*$sql = 'SELECT * FROM formlist ORDER BY id ASC';
$db = Yii::$app->db;
$formlist = $db->createCommand($sql)->queryAll();*/
// same of ->
$formlist = Formlist::find()->orderBy(['id'=>SORT_ASC])->all();
if ($forminfo->load(Yii::$app->request->post()) && $model->load(Yii::$app->request->post())) {
$forminfo->save(false); // skip validation as model is already validated
$model->forminfo_id = $forminfo->id; // no need for validation rule on user_id as you set it yourself
$model->save(false);
Yii::$app->getSession()->setFlash('success', 'You have successfully saved your data.');
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
'forminfo' => $forminfo,
'formlist' => $formlist,
]);
}
}
For accessing tabular input you should use loadMultiple('yourModel')
or a loop on
$post= Yii::$app->request->post());
foreach ($post['your_model'] as $key => $myModel) {
// $myModel contain the current model
}
this yii2 guide could be useful http://www.yiiframework.com/doc-2.0/guide-input-tabular-input.html
Related
I need development something similar a quiz.
I have 3 tables:
quiz, quiz_questions, quiz_questions_answers.
I render the questions / answers like this in form.
<?php foreach ($modelQuestions as $modelQuestion): ?>
<?= $modelQuestion->question ?> <br/>
<?= $form->field($modelMatch, 'answer[]')->textarea(['rows' => 6]) ?>
<?php endforeach; ?>
in controller i need save id_quiz and obs in table quiz, but i need save in many-to-many table quiz_questions_answers like id_quiz, id_question and answer for each answers.
I'm trying this in foreach loop, but how i get the "id_question" for each answer?
public function actionCreate()
{
$model = new Quiz();
$modelMatch = new QuizQuestionsAnswers();
$modelQuestions = QuizQuestions::find()->all();
if ($model->load(Yii::$app->request->post()) && $modelMatch->load(Yii::$app->request->post())){
$model->save();
foreach ($modelMatch->answer as $answer) {
$modelMatch = new QuizQuestionsAnswers();
$modelMatch->id_quis = $model->id;
$modelMatch->id_question = ????;
$modelMatch->answer = $answer;
$modelMatch->save();
}
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
'modelMatch' => $modelMatch,
'modelQuestions' => $modelQuestions,
]);
}
}
this is a scenario create, and after i need prepare this for the scenario update.
i'm lost..
the schema database is:
You should add the id_question as the hidden input and pre-populate the field as you have the question already saved in the database and use tabular approach for field names you should have the [] in the start not in the end, also you should group the answer with the question by using the $modelQuestions index so the answer and the question that it belongs to all are in separate arrays see the below code
<?php foreach ($modelQuestions as $index=>$modelQuestion): ?>
<?php echo $modelQuestion->question ?> <br/>
<?php echo $form->field($modelMatch, "[$index]answer")->textarea(['rows' => 6]) ?>
<?php echo Html::activeHiddenInput($model,"[$index]id_question",['value'=>$modelQuestion->id]) ?>
<?php endforeach;?>
Now when you will submit your for you will see the answers in the post array like below
Array(
.....
'QuizQuestionsAnswers'=>[
[0]=>[
'answer'=>'some answer'
'id_question'=>1,
],
[1]=>[
'answer'=>'some answer',
'id_question'=>2,
],
],
.....
)
Now you should save every answer. And for doing this you should use the transactions so that if any of the answers is not validated according to the model rules it should throw an error and should not save any of the answers or the quiz.
So you should change the code to the below
public function actionCreate()
{
$model = new Quiz();
$modelMatch = new QuizQuestionsAnswers();
$modelQuestions = QuizQuestions::find()->all();
if ($model->load(Yii::$app->request->post())) {
$transaction = Yii::$app->db->beginTransaction();
try {
if (!$model->save()) {
throw new \Exception(implode("<br />", ArrayHelper::getColumn($model->errors, '0')));
}
foreach (Yii::$app->request->post('QuizQuestionsAnswers', []) as $answer) {
$modelMatch = new QuizQuestionsAnswers();
$modelMatch->id_quis = $model->id;
$modelMatch->id_question = $answer['id_question'];
$modelMatch->answer = $answer['answer'];
if (!$modelMatch->save()) {
throw new \Exception(implode("<br />", ArrayHelper::getColumn($modelMatch->errors, '0')));
}
}
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
} catch (\Exception $e) {
$transaction->rollBack();
Yii::$app->session->setFlash('danger', $e->getMessage());
}
}
return $this->render('create', [
'model' => $model,
'modelMatch' => $modelMatch,
'modelQuestions' => $modelQuestions
]);
}
Sending form data from one action to another
<?php $form = ActiveForm::begin(['action' =>'site/roomsearch','method' => 'post']); ?>
<?= $form->field($model, 'arrival')->label(false) ?>
<?= $form->field($model, 'departure')->label(false) ?>
<?= Html::submitButton('Send', ['class' => 'btn btn-white']) ?>
<?php ActiveForm::end(); ?>
index page has the above form from which sending data to actionRoomsearch()
actionindex():
public function actionIndex()
{
$model = new \yii\base\DynamicModel(['arrival','departure','adult','child']);
if($model->load(Yii::$app->request->post()))
{
$arrival = $model->arrival;
$departure = $model->departure;
return $this->redirect([
'roomsearch',
'arrival' => $arrival ,
'departure' => $departure
]);
}
return $this->render('index', ['model'=>$model]);
}
actionroomsearch():
{
$post = Yii::$app->request->post();
$arrival = $post['arrival'];
$departure = $post['departure'];
return $this->render('roomsearch',[
'arrival' =>$arrival,
'departure' => $departure,
]);
}
How to display arrival and departure in roomsearch page?
Created model using \yii\base\DynamicModel
Well as you are redirecting from one action to another , you cant access POST data in the second action. But you can pass it as get parameters
return $this->redirect(\yii\helpers\Url::to([
'/you_controller/your_action',
'arrival' => $arrival ,
'departure' => $departure
]));
In your Second Action
$arrival = yii::$app->request->get('arrival');
$departure = yii::$app->request->get('departure');
Used dynamic model as no data need to save in database
public function actionIndex()
{
$model = new \yii\base\DynamicModel(['arrival','departure']);
$model->addRule(['arrival', 'departure'], 'string', ['max' => 128]);
$arrival = $model->arrival;
if($model->load(Yii::$app->request->post()))
{
$arrival = $model->arrival;
$departure = $model->departure;
$model->save();
}
return $this->render('index', ['model'=>$model]);
}
To get the POST method data in actionRoomsearch
public function actionRoomsearch()
{
$data = yii::$app->request->post();
if(isset($data['DynamicModel']))
{
$arrival = $data['DynamicModel']['arrival'];
$departure = $data['DynamicModel']['departure'];
}
return $this->render('roomsearch',['arrival' =>$arrival,'departure' => $departure]);
}
To display data on page <?php echo $arrival; ?>
Since this is a communication between two request. I will prefer to use Flash
Note: Flash will be deleted automatically after the next request.
public function actionIndex()
{
$model = new \yii\base\DynamicModel(['arrival', 'departure', 'adult', 'child']);
if($model->load(Yii::$app->request->post()))
{
Yii::$app->session->setFlash('arrival', $model->arrival);
Yii::$app->session->setFlash('departure', $model->departure);
return $this->redirect(['roomsearch']);
}
return $this->render('index', ['model'=>$model]);
}
In the room-search page
public function actionRoomSearch()
{
$session = Yii::$app->session;
$arrival = $session->hasFlash('arrival') ? $session->getFlash('arrival') : null;
$departure = $session->hasFlash('departure') ? $session->getFlash('departure') :null;
//Do whatever you like with the data
}
The reason I prefer this method over $_GET is because there are times
where you have to send security sensitive data over pages and you don't
want it revealed in the browser's address bar.
E.g ID that is posted in an hidden field.
I want to create record where the particular field to be save contains the value of current model's id plus the format I made.
To get the id value I've tried to make Controller like this:
public function actionCreate()
{
$model = new NomorSurat();
if ($model->load(Yii::$app->request->post()))
{
// Save nosurat field with particular format name
$model->save(); // I save to get the current ID here, but return value still nothing
$number = $model->id;
$bulan = date('m');
$tahun = date('Y');
// Save with current id + custom format
$model->nosurat = $number.'/'.'BTPN-TMH'.'/'.Yii::$app->joenmarz->romanic_number($bulan).'/'.$tahun;
... // some stuff
// Then save it all, once again
$model->save();
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
But the variable $number saved in nosurat field returns only the custom format I've made, when I tried it in my View:
...
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'nosurat',
... // some attributes
],
]) ?>
Here's screenshot of the result:
Just add a method to your model which returns the current id and what you have saved in your database on the attribute nosurat like below and use this function for display.
public function getNosuratDisplay()
{
return $this->id.$this->nosurat;
}
This of course would make it more difficult if you want to query for that attribute because the id isn't saved in the database.
So i guess the best solution would be to generate and save this attribute in afterSave (e.g. only generate the id in insert mode i guess this is what you want).
public function generateNosurat()
{
$number = $this->id;
$bulan = date('m');
$tahun = date('Y');
$this->nosurat = $number.'/'.'BTPN-TMH'.'/'.Yii::$app->joenmarz->romanic_number($bulan).'/'.$tahun;
}
public function afterSave($insert, $changedAttributes)
{
parent::afterSave($insert, $changedAttributes);
if ($insert) {
$this->generateNosurat();
$this->save();
}
}
I am using yii2 advanced template improved
Not sure if relevant to problem/a solution but to get to the category I have a form with some javascript which on change redirects the user to the category selected.
I have the following code which allows me to access the posts within that category id I go to localhost:8888/advanced/article/category?id=1
The problem at the minute is that if I call getCategoryName function in my model from my category view the id parameter isn't being passed to the model function therefore when using getCategoryName defaults to sport.
public function actionCategory($id)
{
$model = new Article();
$searchModel = new ArticleSearch();
$query = Article::find()
->where(['category' => $id]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
return $this->render('category', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'model'=>$model,
]);
}
Then within my view I use the following which works to an extent in terms of executing the model function, however I am unsure on how to pass the parameter/current category id to the model function. The below code work for the _index & in the single article view.
<?= $model->CategoryName ?>
This is my model function
public function getCategoryName($category = null)
{
$category = (empty($category)) ? $this->category : $category ;
if ($category === self::CATEGORY_ECONOMY)
{
return Yii::t('app', 'Economy');
}
elseif ($category === self::CATEGORY_SOCIETY)
{
return Yii::t('app', 'Society');
}
else
{
return Yii::t('app', 'Sport');
}
}
Use something like this, in your view
$request = Yii::$app->request;
$id = $request->get('id');//get id from request or change according to your requirement
echo $model->getCategoryName($id);//full method name here
Try to use this. change === to ==:
public function getCategoryName($category = null)
{
$category = (empty($category)) ? $this->category : $category ;
if ($category == self::CATEGORY_ECONOMY)
{
return Yii::t('app', 'Economy');
}
elseif ($category == self::CATEGORY_SOCIETY)
{
return Yii::t('app', 'Society');
}
else
{
return Yii::t('app', 'Sport');
}
}
So can someone explain this to me?
I'm trying to write an edit action and am a bit unsure of why the following does not work:
public function edit($id = null) {
if (!$id) {
throw new NotFoundException('NO ID HAS BEEN SUPPLIED');
}
$data = $this->User->findById($id);
if(!$this->request->is('post')) { $this->request->data = $data; }
if($this->request->is('post') || $this->request->is('put')) {
$this->User->id = $id;
$this->User->save($this->request->data);
$this->redirect(array('action'=>'index'));
}
}
And by not working, I mean, that while it does pre-populate the form with data gathered from findById($id).. it doesn't update the database with the new inputs after the form has been sent.
I have replaced this:
if(!$this->request->is('post'))
With the following:
if($this->request->is('get'))
And suddenly, it works fine. It updates the row with the new values gathered from the post. However, I do not understand what's happening here. Why is it that !$this->request->is('post), does NOT work, while $this->request->is('get') DOES work?
Surely, when the action is first called it is called using a GET request? Doesn't that request qualify as !$this->request->is('post')?
EDIT:
below is the ctp: app/View/Users/edit.ctp
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend><?php echo __('edit User'); ?></legend>
<?php
echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->input('role');
// echo $this->Form->input('role', array(
// 'options' => array('admin' => 'Admin', 'regular' => 'Regular')
//));//
?>
</fieldset> <?php echo $this->Form->end(__('Submit')); ?>
By default Cake uses 'PUT' method for 'edit' action and 'POST' for 'add'. so you need to check $this->request->isPut() (or $this->request->is('put')). Look for a hiiden field *_method* that automatically generated by $this->Form->create() method in your view.
If 'id' property is set in data passed to view Cake creates 'edit' form and 'add' if no 'id'.
Do it this way
public function edit() {
$id = $this->params['id'];
if (!$id) {
throw new NotFoundException('NO ID HAS BEEN SUPPLIED'); }
$data = $this->User->findById($id);
if(!$this->request->is('post')) { $this->request->data = $data; }
if($this->request->is('post') || $this->request->is('put')) {
$this->User->id = $id;
$this->User->save($this->request->data);
$this->redirect(array('action'=>'index'));}
passing id to edit from url is not safe way... $this->params['id'] will have your post id so
with it $this->request->is('put') will work.