Laravel set default value if request value is null - laravel

I'm trying to set a default value to a laravel migration. I'm using SQLite.
When I try to insert a record with the field where a default value is assigned to, an error returns: SQL error or missing database (table customers has no column named country)
This is the migrationscript:
php
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('contact_person_first_name');
$table->string('contact_person_name');
$table->string('contact_person_email_address');
$table->string('address');
$table->string('zipCode');
$table->string('city');
$table->string('country')->default("BELGIË");
$table->string('vat_number')->default("BE");
$table->timestamps();
The controller:
* Store a newly created resource in storage.
*
* #param CreateCustomerRequest $request
* #return \Illuminate\Http\RedirectResponse
*/
public function store(CreateCustomerRequest $request)
{
Customer::create($request->validated());
return response()->redirectTo('/customers');
}
The request:
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string|min:2|max:255',
'contact_person_first_name' => 'required|string|min:2|max:255',
'contact_person_name' => 'required|string|min:2|max:255',
'contact_person_email_address' => 'required|email',
'address' => 'required|string|min:2|max:255',
'zipCode' => 'required|string|min:4|max:10',
'city' => 'required|string|min:2|max:255',
'country' => 'nullable|string|min:2|max:255',
'vat_number' => 'nullable|min:12|max:12'
];
}
The sql script I want to execute:
Some screenshots from the database GUI

Another way: Define Mutators in the Model-Class.
With Mutators you can define, what is to set as database-value for a given value.
Look in Laravel/Docs/Eloquent/Mutators: https://laravel.com/docs/8.x/eloquent-mutators
In Customer.php add methods.
public function setCountryAttribute($value)
{
$this->attributes['country'] = $value ?? 'BELGIË';
}
public function setVatNumberAttribute($value)
{
$this->attributes['vat_number'] = $value ?? 'BE';
}

#Case 1: if input is null => store a default value
#Solution 1 - Set default value directly before saving
public function store(CreateCustomerRequest $request)
{
// Retrieve the validated input data...
$validated = $request->validated();
$validated['need_to_have_default_value'] = $validated['need_to_have_default_value'] ?? $defaultValue; // Replace $defaultValue with value that you want to set as default
Customer::create(validated );
#Solution 2 - Set default value in FormRequest => prepareForValidation()
if you are not familiar with laravel form request validation see this link: https://laravel.com/docs/8.x/validation#form-request-validation
/**
* Prepare the data for validation.
*
* #return void
*/
protected function prepareForValidation()
{
$this->merge([
'need_to_have_default_value' => $this->need_to_have_default_value ?? $defaultValue // Replace $defaultValue with value that you want to set as default
]);
}
#Case 2: if input is null => store null
For this case you just need to add nullable() to your migration.
$table->string('set_null_if_null')->nullable();
#Case 3: if input is not set/send => store default value
In this case, the default() will make sense; so it just need to add default() to your field in migration. like below:
$table->string('set_default_if_not_present')->default('any_default_value');
#Case 4: if input is not set/send => store null value
This case is duplicate of case 2
Hope help !

you have set a default value in database layer. but it is not nullable. this is causing the problem here. your request country is null and you are assigning that null value when creating new row. either you have to use nullable to insert null value or you have to set a value when creating.
for database
$table->string('country')->nullable()->default("BELGIË");
this is not a good solution for your case. so you can use something
Customer::create([
'name' => $request->name,
'country' => $request->country ?? 'BELGIË',
//other attributes
]);

I solved it by adding nullable in the migration and then check if value is null.
$customer = Customer::create($request->validated());
if ($customer->country == null) $customer->country= "BELGIË";
if ($customer->vat_number == null) $customer->vat_number= "BE";
$customer->save();
It's less work than putting every value in the create.

Try this if none of the above works
isset(request->requested_value)?requested_value:default_value

like use
public function rules()
{
$rules = [
'column_name' => ['required'], //boolean type
];
return $rules;
}//end of rul
protected function prepareForValidation()
{
$this->merge([
'column_name' => request()->has('column_name') ?? '0',
]);
}//end of fun

Related

Laravel mutator do not set model attribute automatically

In My project there is a PackageRequest model and this model have a tracking_code.
I want to set this attribute automatically with a mutator.
this is my mutator:
public function setTrackingCodeAttribute()
{
$code = mt_rand(1000000, 9999999);
$this->attributes['tracking_code'] = "$code";
}
but when I save new request into database there is no tracking_code
this is my part of code that create new PackageRequest:
public function store(Request $request)
{
$input = $request->only(['requested_time', 'address_id']);
$valid = validator($input, [
'requested_time' => 'required|date',
'address_id' => 'required|numeric|exists:addresses,id'
]);
if ($valid->fails())
return Response::fail($valid->errors());
$package_request = new PackageRequest($input);
$package_request->user_id = \Auth::id();
$package_request->status = 'waiting';
if(!$package_request->save())
return Response::error(__('errors.save_data', ['attr' => __('errors.attribures.package_request')]));
return Response::success(PackageRequest::find($package_request->id), 201);
}
The mutator will receive the value that is being set on the attribute, allowing you to manipulate the value and set the manipulated value on the Eloquent model's internal $attributes property.
The mutator will be automatically called when you attempt to set the value to attribute tracking_code, and you are not setting anything to it. What you need is setting default value to tracking_code before creating, so you can add these codes in model PackageRequest:
protected static function boot()
{
parent::boot();
static::creating(function($package_request)
{
$package_request->tracking_code = mt_rand(1000000, 9999999);
});
}

Route Model binding fails when using Form request

The Route model binding fails when I use the FormRequest to validate the request. To be more specific, when I try to access the parameters in the form request and give the following error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'name:\"moniersa\"' in 'where clause'
(SQL: select count(*) as aggregate from `users` where `email` = a.monier2130#gmail.com and
`name:\"moniersa\"` <> {\"id\":5 and `email:\"a`.`monier2130#gmail`.`com\"` =
email_verified_at:null and `admin:1` = verified:0 and `created_at:\"2020-02-11 22:33:33\"` =
updated_at:\"2020-02-11 23:17:40\"})
The code of the update method:
public function update(User $user, UpdateUserRequest $request)
{
$data = $this->extract_data($request);
$user->update($data);
return response()->json(['data' => $user], 200);
}
The code of the rules function in the Update request:
public function rules()
{
return [
'name' => 'required|string|min:3|max:40',
'email' => 'required|email|unique:users,email,' . $this->user,
'password' => 'required|string|min:9|confirmed'
];
}
Whenever, I remove the User hint from the update method or $this->user from the update request file, everything works fine. Any clue about what is the problem is?
Route model binding means you do not need to use $user = User::findOrFail($user); anymore,
public function update(User $user, UpdateUserRequest $request)
{
$user = User::findOrFail($user);// this line is redundant, you can remove it.
$data = $this->extract_data($request);
$user->update($data);
return response()->json(['data' => $user], 200);
}

Opposite of required_if in laravel using multiple value evaluation

How to validate must null if another field has specific value or not null
In my case it is the opposite of required_if with multiple values
$rule = array(
'selection' => 'required',
'stext' => 'required_if:selection,2|required_if:selection,3',// stext should be null if selection is 2 or 3
);
And if needed how to perform own validation?
So in your example you can do something like this:
$rule = array(
'selection' => 'required',
'stext' => 'required'
);
// override the rule
if(in_array(request('selection'), [2, 3]))
{
$rule['stext'] = 'nullable';
}
This means if the selection is 2 the field will be required and if the selection field has any other value the stext field will be required.
I am not sure if I understood your question correctly. In any case the opposite of required_if is required_without so you can use that one if you want this field to be required even if the selection is empty.
With custom rule your passes method should look like this:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CustomRule implements Rule
{
protected $selection;
public __construct($selection)
{
$this->selection = $selection;
}
public function passes($attribute, $value)
{
return $value === null && in_array($this->selection, [2, 3]);
}
}
You use it like this:
$rule['stext'] = [ new CustomRule(request('selection') ]
I try to extend the validation rule. put the following in AppServiceProvider:
Validator::extend('null_if', function ($attribute, $value, $parameters, $validator) {
$other = $parameters[0];
$other_value = array_get(request()->toArray(), $other);
if ($parameters[1] == $other_value) {
return empty($value);
}
return true;
});
Tell me if it's work or what error given to you.

Laravel Map DB Column Names Using Proper Convention to Actual DB Column Names in Model

We're building a portal to replace part of an existing application as step one, but the DB schema holds to absolutely no conventions. Aside from the lack of any constraints, indexes, etc the names of columns are not descriptive and not snake-cased.
Is it possible to map DB table column names so that the portal uses proper descriptive and snake-cased column names like first_name but writes to the actual database column first to at least have the portal be a first step towards cleaning up the tech debt?
For example, similar to how the table name (Model::table) can be set if the table name doesn't follow convention:
Example
private $columns = [
// convention => actual
'first_name' => 'first',
'last_name' => 'last',
'mobile_phone' => 'phone',
'home_phone' => 'otherPhone', // seriously!?
];
I've looked through Model and the HasAttributes trait, but I'm still hoping that this might exist, or someone has found a way to do this as a temporary solution.
You can create a parent class for all your models:
abstract class Model extends \Illuminate\Database\Eloquent\Model {
protected $columns = [];
public function attributesToArray()
{
$attributes = parent::attributesToArray();
foreach ($this->columns as $convention => $actual) {
if (array_key_exists($actual, $attributes)) {
$attributes[$convention] = $attributes[$actual];
unset($attributes[$actual]);
}
}
return $attributes;
}
public function getAttribute($key)
{
if (array_key_exists($key, $this->columns)) {
$key = $this->columns[$key];
}
return parent::getAttributeValue($key);
}
public function setAttribute($key, $value)
{
if (array_key_exists($key, $this->columns)) {
$key = $this->columns[$key];
}
return parent::setAttribute($key, $value);
}
}
Then override $columns in your models:
protected $columns = [
'first_name' => 'first',
'last_name' => 'last',
'mobile_phone' => 'phone',
'home_phone' => 'otherPhone',
];
The proper way is to use accessors and mutators.
Defining An Accessor
public function getFirstNameAttribute() {
return $this->first;
}
Then, you can access the value by $model->first_name.
Defining A Mutator
public function setFirstNameAttribute($value) {
$this->attributes['first'] = $value;
}
Then, you can mutate the value for example:
$model->first_name = 'first_name';
$model->save();

add Symfony Assert in a Callback

I, i have to add an Assert to an atribute when other atribute is equal than something. Like this:
/**
* #Assert\Callback(methods={"isChildMinor",)
*/
class PatientData
{
/**
* #Assert\Date()
*/
public $birthday;
public $role;
public function isChildMinor(ExecutionContext $context)
{
if ($this->role == 3 && check #assert\isMinor() to $birtday) {
=>add violation
}
}
so, i want check if the patient is minor (with assert or somethings else) if the role is equal than 3. How do this?
There are several ways to do, what you want.
1) You could make it right in the form. Like that:
use Symfony\Component\Validator\Constraints as Assert;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$yourEntity = $builder->getData();
//here you start the field, you want to validate
$fieldOptions = [
'label' => 'Field Name',
'required' => true,
];
if ($yourEntity->getYourProperty != 'bla-bla-bla') {
$fieldOptions[] = 'constraints' => [
new Assert\NotBlank([
'message' => 'This is unforgivable! Fill the field with "bla-bla-bla" right now!',
]),
],
}
$builder->add('myField', TextType::class, $fieldOptions);
2) Other way - is to make your custom validation callback in your Entity and play with direct asserts there. It's possible, I think.
3) But the optimal way, from my point of view - is to use several asserts with validation groups. You need to specify Assert\isMinor(groups={"myCustomGroup"}) on birthday field. And then, in your form:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'validation_groups' => function (FormInterface $form) {
$yourEntity = $form->getData();
if ($yourEntity->role !== 3) {
return ['Default', 'myCustomGroup'];
}
return ['Default'];
},
Hope this'll be helpful for you.

Resources