Im new to Yii, and would appreciate any help.
I need to create a page with multiple choice poll. My models look like this:
PollQuestion:
id int
title varchar
PollAnswer
id char //one letter - answer option
title
question_id //FK pool_question(id)
PollResult
user_id int
question_id int //FK poll_question(id)
answers //will be stored like A,B,C
indicated_answer //alternaive answer specified by user
Sample question looks like:
What do you think about us?
(checkbox)A. Good
(checkbox)B.Bad
(checkbox)C.Other (indicate) (textbox goes here)
Im not sure if Im doing it right, my controller:
public function actionSurvey($user_id)
{
$model = [new PollResult];
foreach($model as $model_item){
$model_item->user_id= $user_id;
if ($model_item->load(Yii::$app->request->post())) {
//only one item received, why??
}
}
return $this->render('survey', ['model' => $model]);
}
View:
<?php $form = ActiveForm::begin(); ?>
<?php foreach(PollQuestion::find()->all() as $question) {?>
<?php foreach($model as $model_item) { ?>
<p><?=$question->title?></p>
<?= Html::activeHiddenInput($model_item , "user_id"); ?>
<?= $form->field($model_item, 'answers')->checkboxList(ArrayHelper::map($question->pollAnswers, 'id', 'title')?>
<?= $form->field($model_item, 'indicated_answer') ->textInput()?>
<?php } }?>
<div class="form-group">
<?= Html::submitButton(Yii::t('app', 'Send'), ['class' => 'btn btn-success' ]) ?> </div>
<?php ActiveForm::end(); ?>
The problem is that in controller i receive only one item in array. Im not sure what am I doing wrong.
My suggestion, you need an extra form model to do that.
You can see how to create form model on http://www.yiiframework.com/doc-2.0/guide-input-forms.html.
The form model you create at least has this attributes:
answers[]
indicated_answer[]
and you can save input from user to that attributes and save them into your ActiveRecord model.
It is correct that one model entry is returned. In your form, you are creating a single model and passing that to the form.
public function actionSurvey($user_id)
{
$model = [new PollResult];
// ...
return $this->render('survey', ['model' => $model]);
}
You can then expect a single model back.
Have a look at this related issue on how you can solve this.
Utilising Yii2.0 checkboxlist for Parent-child relation models
Related
I am new in Yii. I need to create product module to save product data. In that i need to create two table products and product_image to save product data and multiple product images.
Product table
id, category_id, , title ,price, description
Product image table
id, product_id, image
I have created table as above and generated model and CRUD for product table. BUT when I goto add product page I am not getting image upload button. I am getting just product table field in add product page.
Should I created model for two table to get image upload button ?
How to insert data in multiple table in yii ?
thanks in advance.
UPDATES
ProductController :
public function actionCreate()
{
$model = new Products();
$productsImage = new ProductsImage();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
'productsImage'=> $productsImage,
]);
}
}
My Add product form.php
<div class="products-form">
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'category_id')->dropDownList(['0'=>'Select Parents Category']+
ArrayHelper::map(ProductCategory::find()->all(),'id','category_name')
) ?>
<?= $form->field($model, 'title')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'price')->textInput() ?>
<?= $form->field($model, 'description')->textarea(['rows' => 6]) ?>
<?= $form->field($productsImage,'image')->fileInput() ?> //here i am getting error of undefined variable $productsImage
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
In Your products table there is no field for image so you are not getting upload image button. Here is many way you can do this. 1 ) You can create public variable for image button in you products model. suppose you have create public variable in products model like public $productImage and in view file in you can create upload button for image using this code.
`echo $form->fileField($model,'productImage',array('class' => 'btn'));`
2) Second option if you want create productImage model then you need to pass that object from create action of product. suppose in your products controller in create action you can create object of productImages model like below.
$productImages = new productImages;
and you need to pass this model variable in create view like this way
$this->render('create',array(
'model'=>$model,
'productImages'=> $productImages,
));
Here suppose $model is your products model object. and in view file you can create image button like below code.
echo $form->fileField($productImages,'product_image',array('class' => 'btn'));
here 'product_image' is your column name of your product_image table. in controller create action you will get in post object using product_images post after that save data how you want i hope you will get idea what you need to do now. hope it helps you
Yii2 provides a way to handle this situation:
in your product controller:
public function actionCreate()
{
$product = new app\models\Product();
$productImages = new app\models\ProductImage();
if($product->load(Yii::$app->request->post()) && $productImages->load(Yii::$app->request->post()) && Model::validateMultiple([$product, $productImages])) {
// your other file processing code
$product->save();
$productImages->save();
// return/redirection statement
}else {
return $this->render(['create', 'product' => $product, 'productImages' => $productImages]);
}
}
I have a Yii2 form:
<?php $form = ActiveForm::begin(['id' => 'que']); ?>
<?php echo $form->field($model, 'type')
->dropDownList($questionTypes, [
'class' => 'form-control ng-pristine ng-valid ng-touched',
'prompt' => 'Select question type',
'ng-model' => 'que.type',
'ng-change' => 'addAnswerOptions(que);',
]);
?>
<?php ActiveForm::end(); ?>
On the basis of selected dropdown value, I have to add some more fields to the same form of the same model. What fields will be added, is totally depend on the dropdown value.
How can I do this?
From the information you give out here is what I would suggest.
1) Dynamic - no AJAX
Build your form with all the fields you need, just contain each "scenario" in a separate div like follows:
<?php $form = ActiveForm::begin(['id' => 'que']); ?>
<?php echo $form->field($model, 'type')
->dropDownList($questionTypes, [
'class' => 'form-control ng-pristine ng-valid ng-touched',
'prompt' => 'Select question type',
'ng-model' => 'que.type',
'ng-change' => 'addAnswerOptions(que);',
]);
?>
<div class="form-option" data-type="class" style="display:none;">
<?php
// ... fields here for case type == class
?>
</div>
<div class="form-option" data-type="prompt" style="display:none;">
<?php
// ... fields here for case type == prompt
?>
</div>
<div class="form-option" data-type="ng-model" style="display:none;">
<?php
// ... fields here for case type == ng-model
?>
</div>
<div class="form-option" data-type="ng-change" style="display:none;">
<?php
// ... fields here for case type == ng-change
?>
</div>
<?php ActiveForm::end(); ?>
Then you will want to register Javascript code to display the correct blocs depending on which dropdown option was selected.
Bellow is an example using JQuery:
$(document).ready(function(){
$('select.form-control').change(function(){
$('.form-option').hide(); // hide all options if an option is showing
var index = $('select.form-control').index();
$('div[data-type="'+index+'"]').show(); //show the correct fields
});
});
If you're going to go this way I suggest you use AJAX validation for your form. It will avoid you having to deal with a headache on page reload.
Once your form is submitted you will have to handle each case in your controller. You can either use a simple set of if() statements that check the drop down value. Or you can set your model validation scenario according to the drop down value.
The advantage of this is that it will be quicker and you will be able to take advantage of ActiveForm. the cons are that you need to know which fields you want to display for each option, and it doesn't allow you to cumulate n number of fields when you don't know how much n is.
2) Using Ajax
In the event that you want to use ajax calls to load the extra form fields you will have to make a controller/action combination that will return the fields depending on the type that you pass in the GET
This action will generate the html of the fields you want to display. Here's an example:
public function actionAjaxFields($type)
{
$html = '';
if($type == "class")
{
$html .= Html::textInput('Field1');
}
elseif($type == "prompt")
{
$html .= Html::textInput('Field2');
}
else
{
// etc...
}
return $html;
}
Note that you can also pass a user id to this method which will allow you to generate a model and use Html::activeTextInput(), however you will not be able to take advantage of ActiveForm features.
Once this is done, you should bind a function to the change event of the dropdown and use something along the lines of :
var responsePromise = $http.get("controller/ajax-fields", {params: {type: <type-from-dropdown>}});
Unfortunately I do not know much about angularjs so this is the extent of the help I can give on the javascript side of things. I'm sure there's more than enough information on google/stackoverflow about binding events and appending data to the DOM in angularjs to get you running.
Let me know if I can be of any extra help on the Yii2 side.
I have several tables and corresponding models, that is to say, Staffs, Dpmembers, Subjects and Positions tables.
In my Staff model I create hasOne on Department because I want to retrieve data from Department table which is working.
But I have also created more associations of hasMany on Dpmember, Subject and Position models because I want to save the corresponding staff records.
The view newstaff.ctp looks like this
<div class="staff form">
<?php echo $this->Form->create('Staff');?>
<h3><?php echo __('Add a new staff member'); ?></h3>
<?php
echo $this->Form->input('name');
echo $this->Form->input('marital',array('label'=>'Marital status','options'=>array('empty'=>'Choose status','Single'=>'Single','Divorced'=>'Divorced','Married'=>'Married')));
echo $this->Form->input('Children');
echo $this->Form->input('nationality');
echo $this->Form->input('location');
echo $this->Form->input('email');
echo $this->Form->input('phone',array('label'=>'Phone number'));
echo $this->Form->input('nextofkeen',array('label'=>'Next of keen'));
echo $this->Form->input('keenrelation',array('label'=>'Next of keen relationship','options'=>array('Choose option'=>'Choose option','Husband'=>'Husband','Wife'=>'Wife','Guardian'=>'Gaurdian','Child'=>'Child')));
echo $this->Form->input('school');
echo $this->Form->input('award');
echo $this->Form->input('schoolperiod');
echo $this->Form->input('workplace',array('label'=>'Workplace'));
echo $this->Form->input('workposition');
echo $this->Form->input('workperiod');
echo $this->Form->input('dpmember.department.',array('options'=>$department,'empty'=>'Choose Department','label'=>'Department'));
echo $this->Form->input('subject.subjcet',array('options'=>array('Choose option'=>'Choose option','Science'=>'Science','Social Studies'=>'Social studies','English'=>'English','Mathematics'=>'Mathematics'),'label'=>'Subject'));
echo $this->Form->input('position.role',array('options'=>array('Choose option'=>'Choose option','Class teacher'=>'Class teacher','Bursar'=>'Bursar','Cook'=>'Cook'),'label'=>'Position'));
echo $this->Form->submit('Save staff', array('class' => 'btn btn-success', 'title' => 'Click here to add the user') );
?>
<?php echo $this->Form->end(); ?>
</div>
My Staff Model Staff.php like this
<?php
class Staff extends AppModel{
public $hasOne = array(
'Department'=>array(
'className'=>'Department'
));
public $hasMany = array(
'Dpmember'=>array(
'className'=>'Dpmember',
'foreign_key'=>'Dpmember.staff_id'
),
'Subject'=>array(
'className'=>'Subject',
'foreign_key'=>'Subject.staff_id'
),
'Position'=>array(
'className'=>'Position',
'foreign_key'=>'Position.staff_id'
)
);
}
?>
In my StaffsController.php I have a function newstaff() with the code below
public function newstaff() {
/*Create a select form field for departments */
$department = $this->Staff->Department->find('list',array('fields'=>array('Department.title','Department.title')));
$this->set('department', $department);
/*End creation of a select form field for departments */
if (!empty($this->request->data)) {
debug($this->request->data); // returns all data
debug($this->Staff->Subject->subject); // has returned null
debug($this->Staff->Position->position); // has returned null
debug($this->Staff->Dpmember->departement); // has returned null
}
}
I don't know why but for some reason, I have not been able to found out. Running debug($this->request->data) returns expected data.
But accessing individual associated form fields returns null values not the expected data. Please help me.
Thank you
You seem to be using CakePHP 3.0 syntax, while using CakePHP 2.3. The data returned is an array in Cake 2, not an object. So the data is under array keys, like:
$this->request->data['Staff']['Subject']['subject'];
$this->request->data['Staff']['Position']['position'];
$this->request->data['Staff']['Dpmember']['departement'];
Well I think finally I have got the values which are not null. Since I created relationships or rather associations among the models and am using CakePHP 2.3 the right way is
$this->request->data['associateModel']['FormField'];
Therefore I was supposed to do.
$this->request['Subject']['subject'];
$this->request['Subject']['position'];
$this->request['Subject']['department'];
Thank you very much #Oldskool
I am a bit new to the Yii Framework. I am making a product selling website, which has 3 basic models
1. Users model containing the primary key id
2. Products model containing the primary key id
3. Orders model which is basically a mapping between the products and orders. It contains the fields product_id and user_id as foreign keys.
I have made a page where all the products are populated and the logged in user can click on a button on product box to order a particular product.
the code of the link is like this
<?php echo CHtml::link('Order Now',array('order',
'product_id'=>$model->id,
'user_id'=>Yii::app()->user->id)); ?>
(Q1) This is sending a GET request but I want to sent the details as post request. How to do this?
My default controller is the site controller. I have made an actionOrder method in this controller.
The code is:
if(Yii::app()->user->isGuest){
$this->redirect('login');
}else{
$model=new Orders;
if(isset($_POST['products_id']))
{
$model->attributes->products_id=$_POST['product_id'];
$model->attributes->users_id=Yii::app()->user->id;
if($model->save())
$this->redirect(array('index'));
}
$this->render('index');
}
But this code is showing bunch of errors. Also, (Q2) how can I put both products_id and users_id in a single array Orders so that I just have to write $_POST['orders']
Also, (Q3) how can I display a flash message after the save is successful?
Kindly help me to solve my 3 problems and sorry if you feel that the questions are too stupid.
Q1: If you want to use POST request, you're going to have to use a form of sorts, in this case the CActiveForm.
Controller:
public function actionOrder()
{
if(Yii::app()->user->isGuest)
$this->redirect('login');
else
{
$model=new Orders;
if(isset($_POST['Orders']))
{
$model->product_id=$_POST['Orders']['products_id'];
$model->users_id = Yii::app()->user->id;
if($model->save())
{
// Q3: set the flashmessage
Yii::app()->user->setFlash('ordered','The product has been ordered!');
$this->redirect(array('index'));
}
}
$this->render('index', array('model'=>$model)); //send the orders model to the view
}
}
View:
<!-- Q3: show the flash message if it's set -->
<?php if (Yii::app()->user->hasFlash('ordered')): ?>
<?php echo Yii::app()->user->getFlash('ordered'); ?>
<?php endif ?>
...
<?php $form=$this->beginWidget('CActiveForm', array('id'=>'order-form')); ?>
<?php echo $form->hiddenField($model,'products_id',array('value'=>$product->id)); ?> // please note the change of variable name
<?php echo CHtml::submitButton('Order Now'); ?>
<?php $this->endWidget(); ?>
Please note that I have changed the name of the product model variable $model to $product, because we will be using $model for the Orders model for the form.
Q2: In this case I set the users_id value in the controller, so $_POST['Orders'] only contains the value for products_id. In yii you can also mass assign your attributes with:
$model->attributes = $_POST['Orders']
Which basicly means $_POST['Orders'] is already an associative array containing the attribute names and values that are in your form.
Q3: The code shows you how to set and show a flash message after an order is succesfull.
First you have to declare forms send method, if you're using bootsrap it'll be like mine:
<?php $form = $this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'action' => Yii::app()->createUrl($this->route),
'method' => 'post',
'id' => 'activity_timeRpt',
));
?>
Second if you want to send custom inputs, you have to specify, otherwise it'll be like
i'll be back to finish this
For your questions 1 and 2 I'd recomend you to use a CActiveForm class. For example
<?php $form = $this->beginWidget('CActiveForm', array(
'action' => 'you_action_here'
'method'=>'post' // this is optinal parameter, as 'post' is default value
)); ?>
<?php echo $form->textField($model,'product_id'); ?>
<?php echo $form->hiddenField($model,'user_id', array('value'=>Yii::app()->user->id)); ?>
<?php $this->endWidget(); ?>
where $model is instance of Orders class, passed by variables thru controller, or set in view file. After that you can use it in way you wanted $model->attributes = $_POST['orders'] in your action method.
For flash message you can use Yii->app()->user->setFlash('orderStatus', 'Successful'), before redirect( or render ) in your actionOrder. To show it:
<?php if(Yii::app()->user->hasFlash('orderStatus')):?>
<div class="info">
<?php echo Yii::app()->user->getFlash('orderStatus'); ?>
</div>
<?php endif; ?>
For the following database:
TABLES:
user: [id,username]
project: [id,name]
project_user_assignment: [user_id,project_id,role]
When a new project is being created I'd like to show a dropdown with the available users to manage the project and when saving it insert into project_user_assignment the row
[user_id,project_id,'manager']
I'm starter with yii and don't know where (class,method) I must do the insert and how to return an error if in the moment of the insert the query fails
To display a drop down list in the you can use the foliowing code:
<?php echo CHtml::dropDownList(null,
'type',
CHtml::listData(
User::model()->findAll(),
'id',
'username',
),
array('empty' => 'Select a manager from the list ... ', 'id'=>'manager_list')
);?>
to update the corresponding field of the project_user_assignment model use the following:
<?php
<div class="row">
<?php echo $form->labelEx($model,'user_id'); ?> // Here I assume you have the $model variable set to Project_user_assignemenet ... if not (which probably is the case since you are creating a new project, set a new $model2 variable in the controller and use $model2 instead of $model)
<?php echo $form->textArea($model,'user_id'); ?>
<?php echo $form->error($model,'user_id'); ?>
</div>
?>
<script>
$('#manager_list').on('change', function(e) {
$('#Project_user_assignemenet_user_id').val($(this).val()); // Here id maybe wrong! Check them.
return true;
});
</script>
and finally in the controller you just save the model.