An issue with yii validation rule, I have created a signup form with a coupon code for my product. When a user enters coupon code I want to check if the value is present in the coupon table or not.
When the user enter the couponcode I want my validation rule to work, otherwise, if user doesn't enter the code this validation rule should not work, for member signup, I have a member model and for coupon I have a coupon model,
I am using this method in validation rules.
class MemberSignup extends CActiveRecord
{
public $couponcode;
public function rules(){
array('couponcode', 'isCouponCodeExist'),
}//end rules
public function isCouponCodeExist($attribute, $params)
{
$record = Coupon::model()->findByAttributes(array('couponcode' => $this->couponcode));
if($record === null){
$this->addError($attribute, 'Invalid Coupon');
return false;
}
return true;
}
} //class end
any suggesstion will be helpfull for me
<?php
class MemberSignup extends CActiveRecord
{
public $confPassword;
public $couponcode;
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return MemberSignup the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'members';
}
/**
* #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('member_login, member_password,gateway_id, confPassword,email, first_name, packageid,agreed,trafficesource', 'required'),
array('couponcode', 'isCouponCodeExist'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('member_id, member_login', 'safe', 'on'=>'search'),
);
}
public function isCouponCodeExist($attribute,$params){
$record=Coupon::model()->findByAttributes(array('couponcode'=>$this->couponcode));
if($record===null){
$this->addError($attribute, 'Invalid Coupon');
}
}
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'member_id' => 'Member',
'member_login' => 'Username',
'user_id' => 'User',
'member_password' => 'Password',
'confPassword' =>'Confirm Password',
'member_level' => 'Member Level',
'affiliate_id' => 'Affiliate',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'email' => 'Email',
'address' => 'Address',
'city' => 'City',
'state' => 'State',
'country' => 'Country',
'zip' => 'Zip',
'home_phone' => 'Home Phone',
'work_phone' => 'Work Phone',
'refered_by' => 'Refered By',
'location' => 'Location',
'product_id' => 'Product',
'product_path' => 'Product Path',
'product_description' => 'Product Description',
'confirmation_hash' => 'Confirmation Hash',
'status' => 'Status',
'cancellation_reason' => 'Cancellation Reason',
'cancellation_date' => 'Cancellation Date',
'registration_date' => 'Registration Date',
'next_billingdate' => 'Next Billingdate',
'CC_no' => 'Cc No',
'CC_expiry' => 'Cc Expiry',
'last_login' => 'Last Login',
'total_rebillings' => 'Total Rebillings',
'ufa_list_size' => 'Ufa List Size',
'billing_amount' => 'Billing Amount',
'privilege' => 'Privilege',
'maximportlimit' => 'Maximportlimit',
'mailingcount' => 'Mailingcount',
'mailinglimit' => 'Mailinglimit',
'registration_ip' => 'Registration Ip',
'address2' => 'Address2',
'Reactivation_Note' => 'Reactivation Note',
'call_date' => 'Call Date',
'CC_last_four' => 'Cc Last Four',
'slidenumber' => 'Slidenumber',
'domain' => 'Domain',
'registerdomain' => 'Registerdomain',
'gb1_affilateID' => 'Gb1 Affilate',
'agreed' => 'Agreed',
'packageid' => 'Packageid',
'ppid' => 'Ppid',
'sendmeitemizedbill' => 'Sendmeitemizedbill',
'is_superstarmember' => 'Is Superstarmember',
'activationdate' => 'Activationdate',
'reactivationdate' => 'Reactivationdate',
'suspensiondate' => 'Suspensiondate',
'is_editor' => 'Is Editor',
'mobile_phone' => 'Mobile Phone',
'member_quta' => 'Member Quta',
'notification' => 'Notification',
'cancellationrequest' => 'Cancellationrequest',
'siteiD' => 'Sitei D',
'companyname' => 'Companyname',
'companywebsite' => 'Companywebsite',
's3_quota' => 'S3 Quota',
's3_quota_consume' => 'S3 Quota Consume',
'gateway_id' => 'Gateway',
'invoice_id' => 'Invoice',
'couponid' => 'Couponid',
'coupon_success' => 'Coupon Success',
'dont_cancel' => 'Dont Cancel',
'notes' => 'Notes',
'trafficesource' => 'Traffice Source',
'othersource' => 'Othersource',
'couponcode'=>'Coupon Code',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('member_id',$this->member_id);
$criteria->compare('member_login',$this->member_login,true);
$criteria->compare('user_id',$this->user_id);
$criteria->compare('member_password',$this->member_password,true);
$criteria->compare('member_level',$this->member_level);
$criteria->compare('affiliate_id',$this->affiliate_id,true);
$criteria->compare('first_name',$this->first_name,true);
$criteria->compare('last_name',$this->last_name,true);
$criteria->compare('email',$this->email,true);
$criteria->compare('address',$this->address,true);
$criteria->compare('city',$this->city,true);
$criteria->compare('state',$this->state,true);
$criteria->compare('country',$this->country,true);
$criteria->compare('zip',$this->zip,true);
$criteria->compare('home_phone',$this->home_phone,true);
$criteria->compare('work_phone',$this->work_phone,true);
$criteria->compare('refered_by',$this->refered_by,true);
$criteria->compare('location',$this->location,true);
$criteria->compare('product_id',$this->product_id);
$criteria->compare('product_path',$this->product_path,true);
$criteria->compare('product_description',$this->product_description,true);
$criteria->compare('confirmation_hash',$this->confirmation_hash,true);
$criteria->compare('status',$this->status,true);
$criteria->compare('cancellation_reason',$this->cancellation_reason,true);
$criteria->compare('cancellation_date',$this->cancellation_date,true);
$criteria->compare('registration_date',$this->registration_date,true);
$criteria->compare('next_billingdate',$this->next_billingdate,true);
$criteria->compare('CC_no',$this->CC_no,true);
$criteria->compare('CC_expiry',$this->CC_expiry,true);
$criteria->compare('last_login',$this->last_login,true);
$criteria->compare('total_rebillings',$this->total_rebillings);
$criteria->compare('ufa_list_size',$this->ufa_list_size);
$criteria->compare('billing_amount',$this->billing_amount);
$criteria->compare('privilege',$this->privilege,true);
$criteria->compare('maximportlimit',$this->maximportlimit);
$criteria->compare('mailingcount',$this->mailingcount,true);
$criteria->compare('mailinglimit',$this->mailinglimit,true);
$criteria->compare('registration_ip',$this->registration_ip,true);
$criteria->compare('address2',$this->address2,true);
$criteria->compare('Reactivation_Note',$this->Reactivation_Note,true);
$criteria->compare('call_date',$this->call_date,true);
$criteria->compare('CC_last_four',$this->CC_last_four,true);
$criteria->compare('slidenumber',$this->slidenumber,true);
$criteria->compare('domain',$this->domain,true);
$criteria->compare('registerdomain',$this->registerdomain,true);
$criteria->compare('gb1_affilateID',$this->gb1_affilateID,true);
$criteria->compare('agreed',$this->agreed,true);
$criteria->compare('packageid',$this->packageid);
$criteria->compare('ppid',$this->ppid);
$criteria->compare('sendmeitemizedbill',$this->sendmeitemizedbill,true);
$criteria->compare('is_superstarmember',$this->is_superstarmember);
$criteria->compare('activationdate',$this->activationdate,true);
$criteria->compare('reactivationdate',$this->reactivationdate,true);
$criteria->compare('suspensiondate',$this->suspensiondate,true);
$criteria->compare('is_editor',$this->is_editor);
$criteria->compare('mobile_phone',$this->mobile_phone,true);
$criteria->compare('member_quta',$this->member_quta,true);
$criteria->compare('notification',$this->notification,true);
$criteria->compare('cancellationrequest',$this->cancellationrequest,true);
$criteria->compare('siteiD',$this->siteiD);
$criteria->compare('companyname',$this->companyname,true);
$criteria->compare('companywebsite',$this->companywebsite,true);
$criteria->compare('s3_quota',$this->s3_quota);
$criteria->compare('s3_quota_consume',$this->s3_quota_consume);
$criteria->compare('gateway_id',$this->gateway_id,true);
$criteria->compare('invoice_id',$this->invoice_id);
$criteria->compare('couponid',$this->couponid);
$criteria->compare('coupon_success',$this->coupon_success);
$criteria->compare('dont_cancel',$this->dont_cancel);
$criteria->compare('notes',$this->notes,true);
$criteria->compare('trafficesource',$this->trafficesource,true);
$criteria->compare('othersource',$this->othersource,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
If I have understood you correctly, your couponcode is not required and you would like to validate the couponcode only if the user has entered one.
public function rules()
{
return array(
array('field1, field2, field3', 'required'),
array('couponcode', 'isCouponCodeExist'),
);
}
EDIT:
In yii, all validation methods in a model will be executed, even if the field that's being validated is not required. Even though your field couponcode is not required, the validation method isCouponCodeExist() will always be executed.
That means we'll have to edit your code in the method isCouponCodeExist() to allow an empty couponcode, a little something like this:
public function isCouponCodeExist($attribute, $params)
{
if(!empty($this->couponcode))
{
$record = Coupon::model()->findByAttributes(array('couponcode' => $this->couponcode));
if($record === null)
{
$this->addError($attribute, 'Invalid Coupon');
}
}
}
Also, you don't have to return true or false in validation methods. All you need to do is add an error if something is wrong.
Related
I want to get limited numbers of data from database using Yİİ2. I fetched all the record by writing this:
$departures = ArrayHelper::map(
TourDeparture::find()->all(),
'id',
'tour_id'
);
I tried to use limit(5), so that I can get only 5 rows. But I could not. Still, I get the all the rows in the table. How can I achieve that?
Updated: Here is my tourdeparture model
class TourDeparture extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'tour_departure';
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['tour_id', 'start_date', 'end_date', 'price_1adult', 'price_2adult', 'price_3adult', 'price_child', 'price_baby', 'min_guests', 'max_guests', 'status', 'required_min_guest'], 'required'],
[['tour_id', 'min_guests', 'max_guests', 'status', 'required_min_guest'], 'integer'],
[['start_date', 'end_date'], 'safe'],
[['price_1adult', 'price_2adult', 'price_3adult', 'price_child', 'price_baby'], 'number'],
[['tour_id'], 'exist', 'skipOnError' => true, 'targetClass' => Tour::className(), 'targetAttribute' => ['tour_id' => 'id']],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'tour_id' => 'Tour ID',
'start_date' => 'Start Date',
'end_date' => 'End Date',
'price_1adult' => 'Price 1adult',
'price_2adult' => 'Price 2adult',
'price_3adult' => 'Price 3adult',
'price_child' => 'Price Child',
'price_baby' => 'Price Baby',
'min_guests' => 'Min Guests',
'max_guests' => 'Max Guests',
'status' => 'Status',
'required_min_guest' => 'Required Min Guest',
];
}
/**
* Gets query for [[Tour]].
*
* #return \yii\db\ActiveQuery
*/
public function getTour()
{
return $this->hasOne(Tour::className(), ['id' => 'tour_id']);
}
/**
* Gets query for [[TourReservations]].
*
* #return \yii\db\ActiveQuery
*/
public function getTourReservations()
{
return $this->hasMany(TourReservation::className(), ['tour_departure_id' => 'id']);
}
}
$departures = ArrayHelper::map( TourDeparture::find()->limit(5), 'id',
'tour_id' );
I wrote it like above. but ı got all the record
I'm surprised your code worked at all! You are passing the Query class into the map function. ArrayHelper::map is expecting an array and needs the query to be executed using the ->all(). ->limit(5) just adds a new term to the SQL query.
$departures = ArrayHelper::map( TourDeparture::find()->limit(5)->all(), 'id', 'tour_id' );
for retrieve the first 5 rows should be
TourDeparture::find()->orderBy("id")->limit(5)->all()
The code you shared didn't do the limit(5). Anyway, I believe it is caused by the array map,
you may try to simulate the changes as below
$q = TourDeparture::find()->select(['id', 'tour_id'])->limit(5)->asArray()->all();
\yii\helpers\VarDumper::dump($q, $depth = 10, $highlight = true);
For the above, records selected in array form, before array map.
After array map, from here you can compare the changes.
$departures = ArrayHelper::map(
$q,
'id',
'tour_id'
);
\yii\helpers\VarDumper::dump($departures, $depth = 10, $highlight = true);
I'm using a Laravel Json Resource in my controller, as follows
public function index(Request $request)
{
$itemsWithTranslations = MenuItem::where(['menu_id' => $request->id, 'parent_id' => null])
->with(['children', 'translations'])
->orderBy('sort_order', 'asc')
->get();
return MenuItemResource::collection($itemsWithTranslations);
}
Now I would like to generate a collection, inside this collection with the children for the item that's being shown.
The following code works fine. Notice how I commented out the children reference
class MenuItemResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'text' => $this->title,
// 'children' => MenuItemResource::collection($this->whenLoaded('children')),
'data' => [
'id' => [
'value' => $this->id,
'type' => 'hidden'
],
'title' => [
'value' => $this->title,
'type' => 'text',
'label' => 'Title'
],
'resource_link' => [
'value' => $this->resource_link,
'type' => 'text',
'label' => 'Resource Link'
],
'translations' => MenuItemTranslationResource::collection($this->whenLoaded('translations'))->keyBy(function ($translation) {
return $translation['locale'];
})
]
];
}
}
When I uncomment the children, I get the following error
"Call to undefined method Illuminate\Http\Resources\Json\AnonymousResourceCollection::keyBy()"
Is it wrong, to include a Resource inside a resource? Or how should I go about this?
Model
class MenuItem extends Model
{
protected $table = 'menu_items';
protected $fillable = ['menu_id', 'parent_id', 'title', 'order', 'resource_link', 'html_class', 'is_blank'];
public function translations()
{
return $this->hasMany(MenuItemTranslation::class, 'menu_item_id');
}
public function children()
{
return $this->hasMany(MenuItem::class, 'parent_id');
}
}
Extra Information
When I return the following data, it does return empty as a collection for the children.
MenuItemResource::collection($this->children);
This returns
While if I return the children without a collection, it returns them (for 1 item, which is correct)
return $this->children;
returns
you should use ChildrenResource::collection
'children' => ChildrenResource::collection($this->whenLoaded('children'))
hope this works.
create a ChildrenResource class if not exists.
I'm trying to create customized messages for validation in Laravel 5. Here is what I have tried so far:
$messages = [
'required' => 'Harap bagian :attribute di isi.',
'unique' => ':attribute sudah digunakan',
];
$validator = Validator::make($request->all(), [
'username' => array('required','unique:Userlogin,username'),
'password' => 'required',
'email' => array('required','unique:Userlogin,email'),$messages
]);
if ($validator->fails()) {
return redirect('/')
->withErrors($validator) // send back all errors to the login form
->withInput();
} else {
return redirect('/')
->with('status', 'Kami sudah mengirimkan email, silahkan di konfirmasi');
}
But it's not working. The message is still the same as the default one. How can I fix this, so that I can use my custom messages?
Laravel 5.7.*
Also You can try something like this. For me is the easiest way to make custom messages in methods when you want to validate requests:
public function store()
{
request()->validate([
'file' => 'required',
'type' => 'required'
],
[
'file.required' => 'You have to choose the file!',
'type.required' => 'You have to choose type of the file!'
]);
}
If you use $this->validate() simplest one, then you should write code something like this..
$rules = [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|max:250',
];
$customMessages = [
'required' => 'The :attribute field is required.'
];
$this->validate($request, $rules, $customMessages);
You can provide custom message like :
$rules = array(
'URL' => 'required|url'
);
$messages = array(
'URL.required' => 'URL is required.'
);
$validator = Validator::make( $request->all(), $rules, $messages );
if ( $validator->fails() )
{
return [
'success' => 0,
'message' => $validator->errors()->first()
];
}
or
The way you have tried, you missed Validator::replacer(), to replace the :variable
Validator::replacer('custom_validation_rule', function($message, $attribute, $rule, $parameters){
return str_replace(':foo', $parameters[0], $message);
});
You can read more from here and replacer from here
For Laravel 8.x, 7.x, 6.x
With the custom rule defined, you might use it in your controller validation like so :
$validatedData = $request->validate([
'f_name' => 'required|min:8',
'l_name' => 'required',
],
[
'f_name.required'=> 'Your First Name is Required', // custom message
'f_name.min'=> 'First Name Should be Minimum of 8 Character', // custom message
'l_name.required'=> 'Your Last Name is Required' // custom message
]
);
For localization you can use :
['f_name.required'=> trans('user.your first name is required'],
Hope this helps...
$rules = [
'username' => 'required,unique:Userlogin,username',
'password' => 'required',
'email' => 'required,unique:Userlogin,email'
];
$messages = [
'required' => 'The :attribute field is required.',
'unique' => ':attribute is already used'
];
$request->validate($rules,$messages);
//only if validation success code below will be executed
//Here is the shortest way of doing it.
$request->validate([
'username' => 'required|unique:Userlogin,username',
'password' => 'required',
'email' => 'required|unique:Userlogin,email'
],
[
'required' => 'The :attribute field is required.',
'unique' => ':attribute is already used'
]);
//The code below will be executed only if validation is correct.
run below command to create a custom rule on Laravel
ı assuming that name is CustomRule
php artisan make:rule CustomRule
and as a result, the command was created such as PHP code
if required keyword hasn't on Rules,That rule will not work
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CustomRule implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
//return true or false
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The validation error message.';
}
}
and came time using that
first, we should create a request class if we have not
php artisan make:request CustomRequest
CustomRequest.php
<?php
namespace App\Http\Requests\Payment;
use App\Rules\CustomRule;
use Illuminate\Foundation\Http\FormRequest;
class CustomRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules(): array
{
return [
'custom' => ['required', new CustomRule()],
];
}
/**
* #return array|string[]
*/
public function messages(): array
{
return [
'custom.required' => ':attribute can not be empty.',
];
}
}
and on your controller, you should inject custom requests to the controller
your controller method
class FooController
{
public function bar(CustomRequest $request)
{
}
}
You can also use the methods setAttributeNames() and setCustomMessages(),
like this:
$validation = Validator::make($this->input, static::$rules);
$attributeNames = array(
'email' => 'E-mail',
'password' => 'Password'
);
$messages = [
'email.exists' => 'No user was found with this e-mail address'
];
$validation->setAttributeNames($attributeNames);
$validation->setCustomMessages($messages);
For those who didn't get this issue resolve (tested on Laravel 8.x):
$validated = Validator::make($request->all(),[
'code' => 'required|numeric'
],
[
'code.required'=> 'Code is Required', // custom message
'code.numeric'=> 'Code must be Number', // custom message
]
);
//Check the validation
if ($validated->fails())
{
return $validated->errors();
}
$rules = [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|max:250',
];
$customMessages = [
'required' => 'The :attribute field is required.',
'max' => 'The :attribute field is may not be greater than :max.'
];
$this->validate($request, $rules, $customMessages);
In the case you are using Request as a separate file:
public function rules()
{
return [
'preparation_method' => 'required|string',
];
}
public function messages()
{
return [
'preparation_method.required' => 'Description is required',
];
}
Tested out in Laravel 6+
you can customise the message for different scenarios based on the request.
Just return a different message with a conditional.
<?php
namespace App\Rules;
use App\Helpers\QueryBuilderHelper;
use App\Models\Product;
use Illuminate\Contracts\Validation\Rule;
class ProductIsUnique implements Rule
{
private array $attributes;
private bool $hasAttributes;
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct(array $attributes)
{
$this->attributes = $attributes;
$this->hasAttributes = true;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
$brandAttributeOptions = collect($this->attributes['relationships']['brand-attribute-options']['data'])->pluck('id');
$query = Product::query();
$query->when($brandAttributeOptions->isEmpty(), function ($query) use ($value) {
$query->where('name', $value);
$this->hasAttributes = false;
});
return !$query->exists();
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return ($this->hasAttributes) ? 'The Selected attributes & Product Name are not unique' : 'Product Name is not unique';
}
}
Laravel 10.x
If you are using Form Requests, add another method called messages(): array in your request.
class YourRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required',
'email' => 'required|email',
...
];
}
//Add the following method
public function messages(): array
{
return [
'email.required' => 'Custom message for Email Required',
];
}
}
Then the message will be displayed automatically once the request is send from the form.
I have to implement the validation as mentioned in the title that either one of the two fields (email, phone) is required. I am doing this in my model:
[['email'],'either', ['other' => ['phone']]],
And this is the method:
public function either($attribute_name, $params) {
$field1 = $this->getAttributeLabel($attribute_name);
$field2 = $this->getAttributeLabel($params['other']);
if (empty($this->$attribute_name) && empty($this->$params['other'])) {
$this->addError($attribute_name, Yii::t('user', "either {$field1} or {$field2} is required."));
return false;
}
return true;
}
When I access my index page, it gives me this error:
Exception (Unknown Property) 'yii\base\UnknownPropertyException' with
message 'Setting unknown property: yii\validators\InlineValidator::0'
Any help?
If you don't care that both fields show an error when the user provides neither of both fields:
This solutions is shorter than the other answers and does not require a new validator type/class:
$rules = [
['email', 'required', 'when' => function($model) { return empty($model->phone); }],
['phone', 'required', 'when' => function($model) { return empty($model->email); }],
];
If you want to have a customized error message, just set the message option:
$rules = [
[
'email', 'required',
'message' => 'Either email or phone is required.',
'when' => function($model) { return empty($model->phone); }
],
[
'phone', 'required',
'message' => 'Either email or phone is required.',
'when' => function($model) { return empty($model->email); }
],
];
The rule should be:
['email', 'either', 'params' => ['other' => 'phone']],
And method:
public function either($attribute_name, $params)
{
$field1 = $this->getAttributeLabel($attribute_name);
$field2 = $this->getAttributeLabel($params['other']);
if (empty($this->$attribute_name) && empty($this->{$params['other']})) {
$this->addError($attribute_name, Yii::t('user', "either {$field1} or {$field2} is required."));
}
}
Improved variant
['gipsy_team_name', 'either', 'skipOnEmpty'=>false, 'params' => ['other' => 'poker_strategy_nick_name']],
['vkontakte', 'either', 'skipOnEmpty'=>false, 'params' => ['other' => ['odnoklasniki','odnoklasniki']]],
Added 'skipOnEmpty'=>false for forcing validating and 'other' can be array
/**
* validation rule
* #param string $attribute_name
* #param array $params
*/
public function either($attribute_name, $params)
{
/**
* validate actula attribute
*/
if(!empty($this->$attribute_name)){
return;
}
if(!is_array($params['other'])){
$params['other'] = [$params['other']];
}
/**
* validate other attributes
*/
foreach($params['other'] as $field){
if(!empty($this->$field)){
return;
}
}
/**
* get attributes labels
*/
$fieldsLabels = [$this->getAttributeLabel($attribute_name)];
foreach($params['other'] as $field){
$fieldsLabels[] = $this->getAttributeLabel($field);
}
$this->addError($attribute_name, \Yii::t('poker_reg', 'One of fields "{fieldList}" is required.',[
'fieldList' => implode('"", "', $fieldsLabels),
]));
}
$model=new Event('create');
$model->attributes=$_POST['Event'];
if($model->save()){
$pkg = new Package();
$pkg->attributes=$_POST['Package'];
$pkg->event_id = $model->id;
$pkg->save();
}
The Event model gets saved correctly with all the POST variables for Event, while the Package only has the event_id set, but no attributes are set (they are all NULL). What am I doing wrong?
NB: The Event object has been programmed by my predecessor, the Package object is a new addition I did.
EDIT: the whole Package class
class Package extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return 'tbl_package';
}
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('', 'safe', 'on'=>'search'),
array('', 'numerical'),
);
}public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'event' => array(self::BELONGS_TO, 'Event', 'id')
);
}public function attributeLabels()
{
return array(
'event_id' => 'Event ID',
'package_name' => 'Package name',
'event_banner' => 'Event Banner',
'ad_placement' => 'Ad Placement in Event Program',
'logo_on_step' => 'Logo on Step & Repeat',
'use_evt_pics' => 'Usage of Event Pictures',
'exhibition' => 'Exhibition Booth/Space',
'inc_press' => 'Inclusion in Press',
'print_ads' => 'Insertion in Print Ads',
'online_ads' => 'Insertion in Online Ads',
'attendee_bags' => 'Attendee Bags',
'charging_st' => 'Charging Stations',
'cups' => 'Coffee/Water Cups',
'distr_items' => 'Distributable Items',
'lanyards' => 'Lanyards',
'napkins' => 'Napkins',
'notebooks' => 'Notebooks',
'pens' => 'Pens',
'seat_covers' => 'Seat Covers',
'snack_pack' => 'Snack Packaging',
'water_bottles' => 'Water Bottles'
);
} public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('event_banner',$this->event_banner);
$criteria->compare('package_name',$this->package_name);
$criteria->compare('ad_placement',$this->ad_placement);
$criteria->compare('logo_on_step',$this->logo_on_step);
$criteria->compare('use_evt_pics',$this->use_evt_pics);
$criteria->compare('exhibition',$this->exhibition);
$criteria->compare('inc_press',$this->inc_press);
$criteria->compare('print_ads',$this->print_ads);
$criteria->compare('online_ads',$this->online_ads);
$criteria->compare('attendee_bags',$this->attendee_bags);
$criteria->compare('charging_st',$this->charging_st);
$criteria->compare('cups',$this->cups);
$criteria->compare('distr_items',$this->distr_items);
$criteria->compare('lanyards',$this->lanyards);
$criteria->compare('napkins',$this->napkins);
$criteria->compare('notebooks',$this->notebooks);
$criteria->compare('pens',$this->pens);
$criteria->compare('seat_covers',$this->seat_covers);
$criteria->compare('snack_pack',$this->snack_pack);
$criteria->compare('water_bottles',$this->water_bottles);
return new CActiveDataProvider('SponsorshipPackage', array(
'criteria'=>$criteria,
));
}
}
If you want to set attributes through:
$pkg->attributes=$_POST['Package'];
then you have to set rules for any attribute that can be set this way.
You need something like this:
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('package_name', 'required'),
array('package_name', 'length', 'max' => 255),
// or
array('package_name', 'length', 'max' => 255, 'on' => 'insert'),
// at least (when no validation is required):
array('package_name', 'safe'),
// ...
// and so on..
);
}
you need rule for any attribute that you want to set this way.
if there is no rule set for attribute you'll be able to set its value only through $pkg->attribute_name = $value;
rule like array('', 'safe', 'on'=>'search'), or array('', 'numerical'), does nothing (cause attributes list is empty).
read more about validation here
class Package extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return 'tbl_package';
}
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('ad_placement, logo_on_step, ...', 'safe', 'on'=>'search'), //note put here all attrs name that you feel those attrs needs to be assigned from POST like: `$pkg->attributes=$_POST['Package'];`
array('event_id', 'numerical'),
);
}public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'event' => array(self::BELONGS_TO, 'Event', 'id')
);
}public function attributeLabels()
{
return array(
'event_id' => 'Event ID',
'package_name' => 'Package name',
'event_banner' => 'Event Banner',
'ad_placement' => 'Ad Placement in Event Program',
'logo_on_step' => 'Logo on Step & Repeat',
'use_evt_pics' => 'Usage of Event Pictures',
'exhibition' => 'Exhibition Booth/Space',
'inc_press' => 'Inclusion in Press',
'print_ads' => 'Insertion in Print Ads',
'online_ads' => 'Insertion in Online Ads',
'attendee_bags' => 'Attendee Bags',
'charging_st' => 'Charging Stations',
'cups' => 'Coffee/Water Cups',
'distr_items' => 'Distributable Items',
'lanyards' => 'Lanyards',
'napkins' => 'Napkins',
'notebooks' => 'Notebooks',
'pens' => 'Pens',
'seat_covers' => 'Seat Covers',
'snack_pack' => 'Snack Packaging',
'water_bottles' => 'Water Bottles'
);
}
....
}
If it does not work, then you may try, htere is validate() method before save():
$model=new Event('create');
$model->attributes=$_POST['Event'];
if($model->validate()){
$model->save();
}
else{
echo CHtml::errorSummary($model);
}
This will tell what is error.
Never save direct, validate it before save.