Yii2 - Validate attribute with keys - php

I have a problem with attribute key validation.
In model I have property like:
public $_fileds = [];
and My view
<?= $form->field($model, '_fileds[name]') ?>
<?= $form->field($model, '_fileds[type]') ?>
I want to set "_fields[name]" as requierd field. For example I tried add to rules in model something like this:
public function rules()
{
return [
[['_fields[name]'], 'required']
];
}
but this not working :(
Does anyone have any solution?
Sorry for my not good English and thanks in advance for all solutions.

You can write your own validation.
Remove: public $_fileds = [];
public function rules()
{
return [
[['_fields[name]'], 'validateName']
];
}
In same model class:
public function validateName():bool
{
... your checks(if fails return false) ...
return true;
}
But there is one issue: if some of checks fails you, in normal cases, need to set error message using $this->addError() which will correctly work with attributes which are not array elements because as first element of $this->addError() you need to pass attribute name as string where '_fileds' is ok but '_fileds[name]' won't work. So you also need to find a way to return errors if they appear. Same issue with attribute labels and hints.

Related

pass data to edit from the controller to the view in a many to many relationship

Hi everyone i have a many-to-many relationship between the turnos table and the dias table like this:
Currently, I'm doing the CRUD of the turnos table and for each turnos I have to assign many dias, I did it with the attach method.
Now the issue is in the edit method... how am I gonna get the assigned dias that is related to that turno so I can pass it to the view and the user can edit it?
If someone knows it please help me, I would appreciate it very much
//Dias Model
public function turnos()
{
return $this->belongsToMany(Turno::class);
}
//Turnos Model
public function dias()
{
return $this->belongsToMany(Dia::class);
}
// Controller
public function edit(Turno $turno)
{
// $dias = ??
return Inertia::render('Turnos/Editar', [
'turno' => $turno,
'dias' => ??
]);
}
The edit view Should looks like this:
You can load the relation with the load() method and just return the $turno variable that will contain the "turno" and the "dias".
public function edit(Turno $turno) {
$turno->load('dias');
return Inertia::render('Turnos/Editar', [
'turno' => $turno
]);
}
On the client side you can use v-model to fill your inputs.

Laravel - limit FormRequest to certain parameters

In a form request class I use a method like this to validate input data.
class SignupRequest extends FormRequest
{
...
public function rules()
{
return [
'user.email' => 'required_with:user|email',
'user.domain_name' => 'required_with:user|string',
'user.password' => 'required_with:user|string|min:8',
'user.username' => 'required_with:user',
];
}
...
}
Later in a controller I use something like this
$data = $request->get('user', []);
return $this->response($this->userService->create($data, false), 201);
I want somehow to write to my SignupRequest which fields it should allow to be passed. So when later I get $data = $request->get('user', []); I'm sure there are only allowed fields in it.
Is this possible inside the FormRequest?
P.S. I'm aware of $request->only(['field1', 'field2', 'field3']) way, but if I want to limit the fields in SignupRequest extends FormRequest. Because if I use $request->only([...]) in my code several times, I would have to change it several times later. I want to keep it in one place.
You wouldn't need to do this with the request.
One option would be to do something like:
$user = $request->input('user', []);
$data = array_only($user, ['email', 'domain_name', 'password', 'username']);
Or you could even inline it:
$data = array_only($request->input('user', []), ['email', 'domain_name', 'password', 'username']);
Hope this helps!
FormRequest is meant to validate your request data, not control them. You could always extract the inputs you need by doing so.
$data = $request->only(['user.name', 'user.password']);
Edit : Based on your comment, you can do something like this. This allows you to store all the field names within a single request to keep them organised and easier to update.
Add this to your SignupRequest
public function loginData()
{
return array_only($this->input('user', []), ['username', 'password']);
}
Use it in the controller like so
$request->loginData();
return $this->response($this->userService->create($request->loginData(), false), 201);

Check one attribute from a list is set

I have a model like so
class Person extends yii\db\ActiveRecord
{
public $desk_no;
public $mobl_no;
public $faxx_no;
}
I want to add a validation rule which would read something like this in English
One of the *_no attributes is required; I don't care which one.
How do I go about that in yii2?
A bit of a hack but you can use the required validator with conditional validation:
public function rules() {
$oneOfUs = ['desk_no', 'mobl_no', 'faxx_no'];
return [
... //Your other rules here
[$oneOfUs, 'required', 'when' => function($model, $attribute) use ($oneOfUs) {
foreach (array_diff($oneOfUs, [$attribute]) as $f) {
return !!($model->$f);
}
return false;
}]
];
}
The above code works since the condition function will return true if any attribute except the current one is set. This will in turn run therequired validator on the current attribute.
you could use such validation for example
['desk_no', 'required', 'when' => function($model) {
return is_null($model->mobl_no)&&is_null($model->faxx_no);
}, message => "One of the *_no attributes is required; I don't care which one." ],
but if this logic can change, i prefer custom validator

Relational attribute in Yii2 form

I am trying to get to figure out the proper way of handling a form receiving relational data in Yii2. I haven't been able to find any good examples of this. I have 2 models Sets and SetsIntensity, every Set may have one SetsIntensity associated with it. I'm am trying to make a form where you can input both at the same time. I'm not sure how to handle getting the input for a particular field 'intensity' in SetsIntensity.
Where
$model = new \app\models\Sets();
If I put it in the field like this client validation won't work and the attribute name is ambiguous and saving becomes difficult
<?= $form->field($model, 'lift_id_fk') ?>
<?= $form->field($model, 'reps') ?>
<?= $form->field($model, 'sets') ?>
<?= $form->field($model, 'type') ?>
<?= $form->field($model, 'setsintensity') ?>
I would like to do something like this but I get an error if I do
<?= $form->field($model, 'setsintensity.intensity') ?>
Exception (Unknown Property) 'yii\base\UnknownPropertyException' with message 'Getting unknown property: app\models\Sets::setsintensity.intensity'
I could do make another object in the controller $setsintensity = new Setsintensity(); but I feel this is a cumbersome solution and probably not good practice especially for handling multiple relations
<?= $form->field($setsintensity, 'intensity') ?>
relevant code from SetsModel
class Sets extends \yii\db\ActiveRecord
{
public function scenarios() {
$scenarios = parent::scenarios();
$scenarios['program'] = ['lift_id_fk', 'reps', 'sets', 'type', 'intensity'];
return $scenarios;
}
public function rules()
{
return [
[['lift_id_fk'], 'required'],
[['lift_id_fk', 'reps', 'sets','setsintensity'], 'integer'],
[['type'], 'string', 'max' => 1],
['intensity', 'safe', 'on'=>'program']
];
}
public function getSetsintensity()
{
return $this->hasOne(Setsintensity::className(), ['sets_id_fk' => 'sets_id_pk']);
}
SetsIntensity Model
class Setsintensity extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'setsintensity';
}
public function rules()
{
return [
[['sets_id_fk', 'intensity', 'ref_set'], 'required'],
[['sets_id_fk', 'intensity', 'ref_set'], 'integer']
];
}
public function getSetsIdFk()
{
return $this->hasOne(Sets::className(), ['sets_id_pk' => 'sets_id_fk']);
}
}
I was also thinking maybe I could put in a hasOne() relation for the specific attribute 'intensity' in 'Sets'
You should simply try this :
<?= $form->field($model->setsintensity, 'intensity') ?>
EDIT : And because "every Set may have one SetsIntensity", you should check this relation before displaying form, e.g. :
if ($model->setsintensity===null)
{
$setsintensity = new SetsIntensity;
$model->link('setsintensity', setsintensity);
}
PS: link method requires that the primary key value is not null.

Yii2: custom validation for multiple attributes using OR not working

I am trying to write a rule that validates if attribute_a or attribute_b is set;
one of the following attributes must be set : licitatii_publice or licitatiile_atribuite
The following code does not work;
<?php
namespace common\models;
use yii\base\Model;
class AbonamentValidare extends Model {
public $licitatii_publice;
public $licitatiile_atribuite;
public $zone;
public $judete;
public $tari;
public static $targetAttribute = [];
public function rules() {
return [
[['zone'], 'required'],
[['licitatii_publice', 'licitatiile_atribuite', 'tari', 'judete'], 'safe'],
['licitatii_publice', 'validate_tip_licitatie', 'targetAttribute' => ['licitatii_publice', 'licitatiile_atribuite']],
];
}
function validate_tip_licitatie($attribute, $param) {
print_r($attribute);
$this->addError($attribute, 'eroarea');
}
public function attributeLabels() {
return array(
'licitatii_publice' => 'lp',
'licitatiile_atribite' => 'la',
'tari' => 'tari',
'judete' => 'judete',
'zone' => 'zone',
);
}
public function save() {
return false;
}
}
?>
Just wanted to update this answer for Yii2 case.
In Yii2 the validators have a skipOnEmpty attribute which is by default set to true. This implies custom validators will not be called if the field is empty, which might not be the required behavior, especially in this case where either of one attribute is mandatory. In order to fix this issue we need to set the skipOnEmpty to false as shown below.
[['licitatii_publice, licitatiile_atribuite'], 'validate_tip_licitatie', 'skipOnEmpty'=> false],
Well what I have done in a case like this is to create the validator like this:
................
return [
[['zone'], 'required'],
[['licitatii_publice', 'licitatiile_atribuite', 'tari', 'judete'], 'safe'],
[['licitatii_publice, licitatiile_atribuite'], 'validate_tip_licitatie'],
];
............
function validate_tip_licitatie($attribute, $param) {
if(!$this->licitatii_publice && $this->licitatiile_atribuite)
$this->addError($attribute, 'eroarea');
}
In this way you show both fields with an error.
However I have done this in Yii1, but from what I read Yii2 should be the same. The logic is the same.
If you want to show error only for 1 attribute you can always just use
return [
[['zone'], 'required'],
[['licitatii_publice', 'licitatiile_atribuite', 'tari', 'judete'], 'safe'],
[['licitatii_publice'], 'validate_tip_licitatie'],
];
What you are trying to do is more fancy :), I get that. If you really want to use targetAttribute you might have to do it like this
https://github.com/yiisoft/yii2/blob/master/framework/validators/ExistValidator.php
Just build your own validator class.
Well. After reading about the exist validator i believe that is exactly what you need. It has examples on how to use it.

Categories