I'm using yii framework in my current project. I have a page with a form (submitting to database) which defines the required fields in the rules of the model - as standard. On this page, I also have a dynamic form I've built, as a component which pulls additional fields in.
However, I need to be able to also define some of these as required fields. Is there any way of defining required fields outside of the model?
Make following changes in your model:
- Define additional fields as public
- Add 'Required Rule' for additional fields
class ExampleModel extends CActiveRecord {
// Define additional fields as public
public $addField1;
public $addField2;
public $addField3;
public function rules() {
return array(
// Add 'Required Rule' for additional fields
array('existField1, existField2, addField1, addField2, addField3', 'required'),
...
);
}
public function attributeLabels() {
return array(
...,
'addField1' => 'Additional Field 1',
'addField2' => 'Additional Field 2',
'addField3' => 'Additional Field 3',
);
}
}
Hope this help you! Let me know if there is any concern from this.
Related
I'm using OctoberCMS based on Laravel and trying to get a list of products within a form via Record Finder.
The use-case is that the record-finder must show available products based on dynamic condition.
I tried to achieve this via "Scope" option of record finder for related form model but not finding a way to pass the dynamic value to the scope.
Sample Code --
class A extends Model
{
public $belongsTo = [
'product' => [
'Plugin\Models\B',
'key' => 'id',
'scope' => 'specificProduct'
],
];
}
class B extends Model
{
public function scopeSpecificProduct($query , $product_type)
{
return $query->where('product_type', $product_type);
}
}
Here $product_type is the dynamic value which I am trying to pass via record finder and get in scope.
Can anyone suggest that is this a correct way for such requirement or how should I achieve this ?
In your fields definition you have to use the scope attribute
fields:
products:
label: Products
type: recordfinder
scope: specificProduct
With this, the second param of your scope will be the A model that is creating or updating
class B extends Model
{
public function scopeSpecificProduct($query , $model)
{
return $query->where('product_type', $model->depend_attribute);
}
}
I have two models: Cities and Schools. As you already understand Cities can have many schools and taking this into account I have defined my model as follows:
class School extends Model
{
public $fillable = ['city_id' ,'name'];
public function city()
{
return $this->belongsTo('App\City','city_id','id');
}
}
class City extends Model
{
public $fillable = ['name'];
Public function schools()
{
return $this->hasMany('App\School', 'id','city_id');
}
}
But I have faced a pproblem when trying to validate update of a school model. I have to validate whether name of the school is unique for selected city or not. I have defined the rule like this:
$rules = array(
'name' => ['required', Rule::unique('schools')->ignore($id)],
);
$validator=Validator::make(Input::all(),$rules);
But it is not allowing to save a school with existing name in other city than selected. How should I change the rule to ensure that school names can be same if the city is different.
Thank you.
Custom rule
The best solution would be to create a custom rule for this, that accepts the field with the corresponding city name/id as a parameter.
Something like
//Calling the custom rule like this
['name' => 'required|validateSchool:yourFieldNameOfCityHere'];
Declaring the custom validation function in your service provider like this
Validator::extend('validateSchool', function ($attribute, $value, $parameters, $validator) {
$cityName = ($validator->data, $parameters[0]);
//Now check if the $value is already set for the specific city by using normal database queries and comparison
return count(City::whereName($cityName)->schools()->whereName($value)->get()) == 0
});
What does it
The custom validation rule receives the data of the field you give with the function (in the code above it's yourFieldNameOfCityHere), so it knows which city the user chose. With this information, you now can check if there is already a school with the name for the entered city.
At the DB level, it sounds like what you want is a compound uniqueness constraint across name and city_id. Eloquent seems to support passing an array of column names in model definitions. It seems like this requires custom validation, though. See Laravel 4: making a combination of values/columns unique and the custom validator at https://github.com/felixkiss/uniquewith-validator
people..
My problem is:
I have a form, with a Collection, so, I setted a CollectionInputFilter to this Collection..
If i send two block of fields (collections) to validate, and one field of one of this block is validated, the same field in the another one block is automatically validated too, even if is wrong or not filled..
I don't know what to do.. I tried a lot of tips.. but, none worked..
Someone can help me? Or faced the same problem?
Here my code:
class ClienteEnderecoFilter extends CollectionInputFilter
{
public function __construct()
{
$this->add(array(
'name' => 'fieldOne',
'required' => true,
));
}
}
If i send two fieldOne and one is filled, the another one is validated too!
I think you need to set the input filter for each collection item on to the CollectionInputFilter instead of extending it. Like this:
use Zend\InputFilter\InputFilter;
class ClienteEnderecoFilter extends InputFilter
{
public function __construct()
{
$this->add(array(
'name' => 'fieldOne',
'required' => true,
));
}
}
$collectionInputFilter = new CollectionInputFilter();
$collectionInputFilter->setInputFilter(new ClienteEnderecoFilter());
In model:
public function getOptionsGender()
{
array(0=>'Any', 1=>Male', 2=>'Female');
}
In view (edit):
echo $form->dropDownList($model, 'gender', $model->optionsGender);
but I have a CDetailView with "raw" attributes, and it displays numbers instead of genders.
$attributes = array(
...
'gender',
)
What is appropriate way to convert these numbers back to genders? Should I do it in a model, replacing fields such as $this->gender = getOptionsGender($this->gender)? Any github examples will be very appreciated.
I had to choose gender, age, city, country etc. in a few views that are not related to this one. Where should I place my getOptionsGender function definitions?
Thank for your help, the problem is solved.
In model:
public function getGenderOptions() { ... }
public function genderText($key)
{
$options = $this->getGenderOptions();
return $options[$key];
}
In view:
$attributes = array(
array (
'name'=>'gender',
'type'=>'raw',
'value'=>$model->genderText($model->gender), //or $this->genderText(...)
),
);
$this->widget('zii.widgets.CDetailView', array(
'data'=>$model,
'attributes'=>$attributes,
));
The working example can be found here:
https://github.com/cdcchen/e23passport/blob/c64f50f9395185001d8dd60285b0798098049720/protected/controllers/UserController.php
In Jeffery Winsett's book "Agile Web Application Development with Yii 1.1", he deals with the issue using class constants in the model you are using. In your case:
class Model extends CActiveRecord
{
const GENDER_ANY=0;
const GENDER_MALE=1;
const GENDER_FEMALE=2;
public function getGenderOptions(){
return array(
self::GENDER_ANY=>'Any',
self::GENDER_MALE=>'Male',
self::GENDER_FEMALE=>'Female',
);
}
public function getGenderText(){
$genderOptions=$this->genderOptions();
return isset($genderOptions[$this->gender]) ? $genderOptions[$this->gender] : "unkown gender({$this->gender})";
}
}
Then in your CDetailView you would have to alter it from gender to:
array(
'name'=>'gender',
'value'=>CHtml::encode($model->genderText()),
),
If several models have the same data, you may want to create a base model that extends CActiveRecord and then extend the new model instead of CActiveRecord. If this model is the only one with that data (ie User model only has gender), but other views use that model to display data, then I would leave it just in the single model class. Also keep in mind that if you place getGenderOptions in the extended class, and you extend ALL your models, they will all have that option available, but may not have the attributes needed and will throw an error if you aren't checking for it.
All this being said, I still think it is a matter or preference. You can handle it however you want, wherever you want. This is just one example from a book I have specifically on Yii.
I have a CActiveRecord model, and I need to change safe attributes list in that model.
I have defined the safeAttributes method inside my model, like the following :
public function safeAttributes()
{
return array(
'name, bio',
);
}
the problem is 'bio' is not being considered in my safe attribute assign. I tried to dump the model safeAttributeNames attribute in my model, and what I've got was completely different from what safeAttributes should return.
Am I doing this in the right way ?
cheers,
Firas
Assuming that you are using Yii 1.0.x then that is the correct way to do it.
If you are using Yii 1.1.x then it's changed. Have another read of the documentation.
public function rules()
{
return array(
array('username, password', 'required'),
array('rememberMe', 'boolean'),
array('password', 'authenticate'),
array('something', 'safe'),
array('someOtherThing', 'unsafe'),
);
}