Yii framework - Different validation rules depending on selected options - php

Is it possible to create model rules that are dependent from selection?
I have a model "Deposit" which is used to enter the money transfer details..I have drop down list with two possible choices "Cash Transfer","Cheque Transfer", and i have fields cash_deposit_date,bank_name.. which is required only for cash transfer and cheque_date, cheque_no and in_favour_of.. which is required only at the time of cheque transfer.. how can i do that..?
I know i can use scenarios like this,
$model=new Deposit("cash_transfer");
or
$model=new Deposit("cheque_transfer");
but how can I change scenario depending on the value selected in dropdown list?

Couldn't you just do this:
Generated HTML:
<form>
....
<select name="scenario">
<option value="cash_transfer">Cash Transfer</option>
<option value="cheque_transfer">Checque Transfer</option>
</select>
....
</form>
Code:
// allow only lowercase letters and underscore
$scenario = preg_replace('/[^a-z_]/', '', $_POST['scenario']);
if (!empty($scenario)) {
$model = new Deposit($scenario);
} else {
die('Missing scenario!');
}

Extending from jupaju answer,
That dropdown list also a model field(transfer_type), so I have done something like this..
After checking POST values are set, I use $model->scenario = $model->transfer_type==1 ? 'cash_transfer':'cheque_transfer' to change the scenario.
My code is
$model=new Deposit;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Deposit']))
{
$model->attributes=$_POST['Deposit'];
$model->scenario = $model->transfer_type==1 ? 'cash_transfer':'cheque_transfer';
if($model->save())
$this->redirect(array('admin'));
}
$this->render('create',array('model'=>$model));
Now it is working..

I think the best way would be to use a personalized validation rule in your model and then check if the model's "scenario" property is set to one or other option.
You can read more about custom validation rules in here
Hope this helps. Good luck!

This is more simple form me
In your model put:
public $pay_type;
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
...
array('pay_type', 'required'),
array('cash_deposit_date', 'validationTransfer'),
...
);
}
public function validationTransfer($attribute,$params)
{
// this a sample, put all your need
if($this->pay_type=='cash_transfer' and $this->cash_deposit_date==='')
$this->addError('cash_deposit_date','If you will pay to Cash Transfer, enter your cahs deposit date');
// this a sample, put all your need
if($this->pay_type=='cheque_transfer' and $this->cheque_date==='')
$this->addError('cheque_date','If you will pay to Cheque Transfer, enter your cheque date');
// this a sample, put all your need
if($this->pay_type=='cheque_transfer' and $this->cheque_no==='')
$this->addError('cheque_no','If you will pay to Cheque Transfer, enter your Cheque No');
}
In the view into your widget form
<?php echo $form->labelEx($model,'pay_type',array('class'=>'control-label')); ?>
<?php echo $form->dropDownList($model,'pay_type',array("cash_transfer"=>"Cash Transfer","cheque_transfer"=>"Cheque Transfer"),array('class'=>'form-control','empty'=>'Pay Type...')); ?>
<?php echo $form->error($model,'pay_type',array('class'=>'help-block')); ?>
Note: css class like "help-block", "control-label", "form-control" on witget form are optionals, maybe you use Bootstrap 3 and it will looks good

Related

Disabled field name in edit profile joomla

I want to disable the fields, name and last name, in edit profile Joomla, so that user can not modify them. How can I change this?
The best approach, but not the easiest, is to create an user plugin to override form with a onContentPrepareForm method :
public function onContentPrepareForm($form, $data){
if (!($form instanceof JForm)){
$this->_subject->setError('JERROR_NOT_A_FORM');
return false;
}
$form->setFieldAttribute('name', 'readonly', 'true');
$form->setFieldAttribute('lastname', 'readonly', 'true');
return true;
}
There is not a configuration setting to achieve this.
So the easiest approach is to create a template override for the users view.
In the administrator, open the menu Extensions-Templates-Templates, then select your template and choose "Create Overrides" in the top tab:
In the center column, choose com_users - profile and edit.php
The display is done with a loop, starting at line 59 (as of v. 3.6.5) you want to add code to identify the fields you wish to keep readonly, and simply set their readonly property.
This is the kind of code you would add starting at line 59:
<?php foreach ($fields as $field) : ?>
<?php
if ($field->name == 'jform[name]') {
$field->readonly = true;
}
?>
<?php // If the field is hidden, just display the input. ?>
The $field contains something like this:
We are identifying it by name (well by its field name), then setting its readonly property.

SugarCRM Befor_save hook

I use SugarCRM and i try to make a Hook when someone save a opportunity.
This is the situation:
I have the column "Opportunity Amount" and i want to calculate the column "Montant %".
So i have add twoo ligne in the hook:
$hook_array['before_save'] = Array();
$hook_array['before_save'][] = Array(1,'calcul montant heure','custom/modules/Opportunities/calcul.php','calcul','montant');
I add the class file:
<?php
if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
class calcul
{
var $module = "Opportunities";
function montant($bean, $event, $arguments)
{
$bean->Montant_perc = ($bean->amount_usdollar * $bean->Probability (%))/100;
}
}
?>
it does not work but I do not understand why?
thanks for your help
I think that you need to recheck the fields name that you are using in before_save logic hook method becuase it seems to me that you are using field labels instead of field names i.e i think
$bean->Probability (%)
should be
$bean->probability
and as the field saved in db is generally in small letters so you should also check that the field
$bean->Montant_perc
should be
$bean->montant_perc
After making these modification do a Quick Repair and then resave the Opportunity to trigger before_save logic hook

How to get selected from jmultiselect2side in yii and display in a new page

I'm new to yii and I don't understand the extensions much
but I used this extension called jmultiselect2side because I'm trying to make a site where users could reserve stuff like apparatuses in the lab
Anyway, I need a code that would get the Selected Items and then display them in another page for viewing purposes
I haven't put anything in the controller but the name of my controller and model is Apparatus
Here is my view:
<?php
$model= Apparatus::model()->findByAttributes(array('ApparatusCode'=>'1'));
// complete user list to be shown at multiselect order by ApparatusCode
$Apparatus= Apparatus::model()->findAll(
array('order' => 'ApparatusCode'));
?>
<center>
<?php
$this- >widget('application.extensions.jmultiselect2side.Jmultiselect2side',array(
'model'=>$model,
'attribute'=>'ApparatusName', //selected items
'labelsx'=>'Available',
'labeldx'=>'Selected',
'moveOptions'=>false,
'autoSort'=>'true',
'search'=>'Search:',
'list'=>CHtml::listData( // available items
$Apparatus,
'ApparatusCode',
'ApparatusName'),
));
?>
please help as soon as possible :/
put all above elements in a form. Set action for the form. Submit the form then the action in which you are handling this submit request, you can write there
if(isset($_POST))
{
foreach($_POST['Apparatus']['ApparatusName'] as $name)
{
do what ever you want
}
}
$name will represent the each selected item

Multiple _form views on a single create view [Yii]

I'm trying to merge 3 models to create a fourth one. I have model1, model2 and model3 and I want to merge them into modelMaster. I've also created controllers for all of them. When I call modelMaster/create action, I render the modelMaster/create view which renders the modelMaster/_form view. Inside this _form view, I also want to render model1/_form, model2/_form and a CHtml::dropDownList(), wich takes datas from model3. However, this doesn't work. How can I combine these three different views into one another?
If you try to skip the form generate from the _form views and use unique model names, I think you can use this manual: single form with more models
So the generate of the form definition handles always the parent view and the _form's only the inputs
The other way to use single model in views, create a form model by extend CFormModel, and handle the data binding between this model and the wrapped submodels
If you want to nest several forms into one master form you have to adjust the form templates accordingly. All of your modelMaster/create, model1/_form, model2/_form-views create and render a new CActiveForm (and thus several <form> tags).
Since you cannot nest form-elements in html (how should html know which action to pass the data to) you have to avoid this by doing the following:
Extract the inputs of the form you want to nest into a new view, e.g. model1/_formInputs would look like
...
<?php echo $form->labelEx($model,'name'); ?>
<?php echo $form->textField($model,'name');
<?php echo $form->error($model,'name');
...
alter the model1/create and the other views and get a reference to the form created there, by assigning the return of $this->beginWidget to the variable $form (if not already done):
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'foo',
)); ?>
replace the former input fields with
<?php $this->renderPartial('model1/_formInputs', array('form' => $form); ?>
Now, for example the old model1/create-view should work as expected
To get your multi-model-form working you just have to get the reference to the form created in modelMaster/create and use it to renderPartial all */_formInputs you require. Please also remember to include the models for the inputs into the renderPartial-call. So modelMaster/create would look something like:
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'foo',
)); ?>
/* Master Inputs here */
// Rendering other models' inputs
<?php $this->renderPartial('model1/_formInputs', array('form' => $form, 'model' => $model1); ?>
<?php $this->renderPartial('model2/_formInputs', array('form' => $form, 'model' => $model2); ?>
/* Render Form Buttons here */
<?php $this->endWidget(); ?>
Submit with Ajax, in Yii it is easy to do and it will keep things easy to understand in the controllers, each controller will have a save and respond with json to confirm the save. There is already ajax validation.
/**
* Performs the AJAX validation.
* #param CModel the model to be validated
*/
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='employee-form')
{
$valid = CActiveForm::validate($model);
if(strlen($valid) > 2) {
echo $valid;
Yii::app()->end();
}
}
}
As you can see I have modified it to return the error if there is one (validate returns [] if it is valid, I should probably check for that instead of strlen >2 ), otherwise let the script continue, in this case it will go to the save function.

In Yii, is there a way to validate tabular input with CActiveForm?

Situation
I used the wiki article on Yii's site, Collecting Tabular Input, to follow as an example.
I don't believe I need to validate tabular input in a traditional sense against multiple models. I only have one model, but I'm dynamically creating the number of fields in the form. Here's a bit more background.
I'm importing CSV files where its headers vary in order among the different files. Before correctly parsing the files, the user needs to map which header would map to what table/column.
I have a single model, ImportParseForm extended from CFormModel. It really only has one rule:
public function rules()
{
return array(
array('header', 'required'),
);
}
Here's a snippet of my view:
<?php foreach($headers as $h => $hItem): ?>
<div class="row">
<?php echo CHtml::label(CHtml::encode($hItem), "[$h]header"); ?> maps to
<?php echo $fParse->textField($mForm, "[$h]header"); ?>
<?php echo $fParse->error($mForm, "[$h]header"); ?>
</div>
<?php endforeach; ?>
Here's a snippet of my controller:
$mForm = new ImportParseForm;
$valid = true;
if (isset($_POST['ImportParseForm'])){
foreach ($headers as $h => $hVal){
if (isset($_POST['ImportParseForm'][$h])){
$mForm->attributes = $_POST['ImportParseForm'][$h];
$valid = $mForm->validate() && $valid;
}
}
if ($valid){
// Process CSV
}
}
If all fields are valid, then it passes as expected. The problem is if one of the fields are invalid (or in this case, empty), then all fields are flagged as invalid.
In Yii 1.1.10, they added CActiveForm::validateTabular(), but it looks like it's for multiple models. Not quite what I have here. But for kicks, I added the following to my controller (removed the other type of validation, of course):
CActiveForm::validateTabular($mForm, array('header'));
The form itself is only valid if the first element is populated. If the first element is populated, it will set all the other elements with that same value (and passes validation).
Question
Basically, can I use CActiveForm to do validation against fields that are dynamically generated (similar to tabular input, but with only one model)?
I was trying to do similar thing, and this is my solution in case of model update form. Here I exploited model validation for update model attributes on value change event, which don't need submit button, and looks simple and fancy. Here is code snippet...
view code:
<?php foreach($modelArray as $model): ?>
<div class="row">
<?php echo $form->textField($model, "[$model->id]attributeName"); ?>
<?php echo $form->label($model, "[$model->id]attributeName"); ?>
<?php echo $form->error($model, "[$model->id]attributeName"); ?>
</div>
<?php endforeach; ?>
controller code:
objArray = array();
foreach($_REQUEST['ModelName'] as $id => $attributes){
$obj = ModelName::model()->findByPk($id);
$obj->attributes = $attributes;
$obj->save();
$objArray[$id] = $obj;
}
echo CActiveForm::ValidateTabular($objArray);
Yii::app()->end();
After reading Collecting Tabular Input a bit closer, I am using "multiple" models. I misunderstood that multiple models would mean multiple different structured models and not just multiple of the same structured model in an array. For example, in the wiki there's a piece that shows what items (array of models) to update: $items=$this->getItemsToUpdate();. My corrected assumption is that that particular method grabs multiple of the same structured model but with different primary keys... or different records. Understanding that, the rest of the article makes more sense ;)
But here's my model solution on how to create a CSV header mapping form.
class ImportParseForm extends CFormModel{
// Model really only has one attribute to check against, the header
var $header;
// New attributeLabels collected and stored on class instantiation
protected $attributeLabels;
// Modify construct so we can pass in custom attribute labels
public function __construct($attributeLabels = '', $scenario = '')
{
if (! is_array($attributeLabels)){
$this->attributeLabels = array($attributeLabels);
}
else{
$this->attributeLabels = $attributeLabels;
}
parent::__construct($scenario);
}
public function rules()
{
return array(
array('header', 'required'),
);
}
public function attributeLabels()
{
// Default mapping
$arr = array(
'header' => 'Header Mapping',
);
// Merge mapping where custom labels overwrite default
return array_merge($arr, $this->attributeLabels);
}
}
Here is a snippet in my controller on what my equivalent to $items=$this->getItemsToUpdate(); (again, the goal is to collect an array of models) would look like
// Get the first row of CSV, assume it's the headers
$tmpCsvRow = explode("\n", $mTmp->data);
$headers = explode(',', $tmpCsvRow[0]);
foreach ($headers as $header){
if (! empty($header)){ // Blank headers are lame, skip them
// Add a new model for each CSV header found into $mForm array
// You can also add in a custom attributeLabel, $header is an actual header name like 'First Name',
// so the new label for the header attribute in ImportParseForm would be 'First Name header' and
// it will show up properly in your CActiveForm view
$mForm[] = new ImportParseForm(array('header' => $header.' header'));
}
}
Push $mForm to your view. Now in your view, iterate through $mForm for your form like so (similar to the wiki article, but I'm using a CActiveForm widget here):
<?php foreach($mForm as $m => $mItem): ?>
<div class="row">
<?php echo $fParse->labelEx($mItem,"[$m]header"); ?> maps to
<?php echo $fParse->textField($mItem, "[$m]header"); ?>
<?php echo $fParse->error($mItem, "[$m]header"); ?>
</div>
<?php endforeach; ?>
Validation works as expected.
If you want to use AJAX validation, use CActiveForm::validateTabular() in your controller (instead of the normal validate()).
Hope this helps other Yii beginners! :)

Categories