Laravel Carbon data missing when date is an empty string - php

In my model I have the following:
protected $dates = ['start_date'];
I am using an input field of type 'date' to select the date. If the user removes the date, its value becomes a null string "".
when updating my model, I get the following error:
exception: "InvalidArgumentException"
file: "C:\www\projects\crm\vendor\nesbot\carbon\src\Carbon\Carbon.php"
line: 582
message: "Data missing"
I can avoid this error by using a mutator like this:
public function setStartDateAttribute($value)
{
if ($value) {
$this->attributes['start_date'] = $value;
} else {
$this->attributes['start_date'] = null;
}
}
Question:
Is there a faster/better way than using a mutator to deal with storing an empty string as a date?

Looking into this a bit deeper:
Middleware updated in 5.4
Laravel 5.4 included two new middleware in the default middleware stack: TrimStrings and ConvertEmptyStringsToNull.
These middleware will automatically trim request input values and
convert any empty strings to null. This helps you normalize the
input for every request entering into your application and not have to
worry about continually calling the trim function in every route and
controller.
From: https://laravel.com/docs/5.4/releases#laravel-5.4
So, when I am grabbing the request object, an empty date field is converted to null. The database allows null on these fields and everything works correctly.
So, through the front end, date fields can be entered and removed without error. When updating manually to an empty string as per your request
\App\Yourmodel::find(7)->update(["your_date_field" => ""]);
I had the same data missing error.
Question is, do you specifically need to pass an empty string or is making the field nullable a better option for you?
\App\Yourmodel::find(7)->update(["your_date_field" => null]);

Related

Laravel Validation Integer accepts empty string?

Im creating some small API with which i can create blog posts through postman. Im using laravel 5 and i encoutered a problem.
In the API call, i can specify a user id, so the post is written by someone else than whoever makes the API call right now. My currently logged in user is specified with a token in postman.
So my problem is now, when i create the API call and specify my user_id as empty string
"userID": ""
it will throw an error, because i specified the id to be an int like so
'userID' => ['integer']
The error is
"Type error: Argument passed to construct() must be of the type integer or null, string given",
Why does it accept an empty string? How can i validate that correctly?
Note that the userID doesn't have to be specified in the post request. If not specified, it will just take the one from the user you are currently logged in with. (Specified in the token)
Using two validation rules together will fix the issue.
required and integer
and as you said, you dont want to make it mandatory:
use these validation rules combination:
nullable|integer
I had this problem. So, I found this description in the laravel docs:
"By default, when an attribute being validated is not present or contains an empty string, normal validation rules, including custom extensions, are not run."
So... when you have an attribute with empty string data, the normal validation rules are not executed.
So... I had an idea to solve this problem which was override the function setAttribute in my models:
public function setAttribute($key, $value)
{
parent::setAttribute($key, $value);
if (is_string($value))
{
$this->attributes[$key] = empty(trim($value)) ? null : $value;
}
}
So... All times that will have to save de model in your database, the empty values will be converted in a null values.
Therefore, if the data is null or integer, use the "nullable | integer" rule to use the validation rule. If the data is an empty string, the validation rule will not be considered, but the data will be converted to an empty string before being saved to the database.
I created a my BaseModel(abstract class) with the method setAttribute and all my models inherit this class.
abstract class BaseModel extends Model
{
public function setAttribute($key, $value)
{
parent::setAttribute($key, $value);
if (is_string($value))
{
$this->attributes[$key] = empty(trim($value)) ? null : $value;
}
} ...
You need to make userId field required as this:
'userId' => 'required|integer'

Laravel nullable validation rule not working

I recently upgraded to laravel 5.4 (from 5.2) to make use of the nullable validation rule.
I have a field act_post_code which can be either an integer OR null. So I provided the following rule in my Request class.
'act_post_code' => 'integer|nullable'
In Postman using form-data, I provide a key = act_post_code with its value = null.
The response I get is the following:
{
"act_post_code": [
"The act post code must be an integer."
]
}
Explanation:
Unfortunately, it seems that nullable is only valid with certain other validations.
For example: 'act_post_code' => 'nullable|integer' will give you the error: "validation.integer"
However, 'act_post_code' => 'nullable|date' works fine.
Fix:
As a work around for these validations, you can make them dynamic. For example, before the validator:
$act_post_code_rules = $request->act_post_code ? 'integer' : '';
then, within the validate:
'act_post_code' => $act_post_code_rules
In order to validate the field act_post_code which can be either be of type integer or nullable, you can try out the following :
When declaring in the migration ,the Schema of the table where there is the column act_post_code declare the column like $table->integer('act_post_code')->nullable();
This one might just work for you to validate 'act_post_code' =>'sometimes|nullable|integer'
One can die and dump request parameters and check whether the actual value is null or "null" (in string). Sometimes when submitting a form via javascript we use FormData() to append data to the form, in those scenarios it may send a null value as in string type "null"
array:5 [
"firstName" => "Kaustubh"
"middleName" => "null" // null as string
"lastName" => "Bagwe"
"contactNumber" => null // null value
"photo" => null
"_method" => "PUT"
]
Open your migration file and make the this field as nullable
For e.g
Schema::create('your_table_name', function (Blueprint $table) {
$table->integer('act_post_code ')->nullable();
});
Make sure it is present in your model file in the fillable section
protected $fillable = ['act_post_code'];
After Some Test I found that nullable rule only work if only the data that we pass really was a null data.
so in my test case i use the validation rule like this :
"counter" => "nullable|numeric"
and in the blade file, I use Form::text('counter','') as element to input my data.
Then i use it with few test case:
When I input the counter data with a non-numeric value it will response with error: "the counter must be a number".
When I input the counter data with a numeric value it will pass the validation test.
When I not input any data to the counter it will pass the validation test.
so i check the data manually using dd($request_data)or if you using ajax just return $request_data and print it using console.log("data") like:
$.ajax({
type:'POST',
data:{_token:"{{ csrf_token() }}",
counter:$('input[name="counter"]').val()
},success:function(data){
console.log(data);
}
});
and found out that when input field is emptied it will give the null value.

How to set default values of fields to empty instead of null

I am using Laravel 5.4 and building API for Android and Iphone. I have set default value to null in phpmyadmin but my mobile developers do not want null values in response. There are many APIs so I am looking for short and perfect method.
I tried to find something in Laravel model that can help me. I tried following code as well.
Also tried setting default value in phpmyadmin but it does not accepts default: "As defined" is equal to empty value.
Third option could be to loop through laravel Model response and convert null to empty or zero based on data type but that will increase processing time and will increase our most of work as well.
public static function boot() { parent::boot();
self::creating(function ($my_model) {
$my_model->some_prop = $my_model->some_prop >= 42 ? $my_model->some_prop: defaultValue();
});}
Is there something in Laravel in Model section or somewhere else where I can set default value to empty fields when field does contain any value or is there any other solution or suggestion means how I can handle this problem?

laravel retrieving request input returns null

Sorry if this question is asked elsewhere, but I've searched everywhere but couldn't find the answer. Well, I'm facing this problem on Laravel 5.0, when i try to get a variable from a request, Im getting null value on Production Server but im getting an empty string on the Development Server. The value is not present on the request, ie the field was empty when the form was submitted. eg.
// ProductController
public function store(Request $request) {
// this field is actually empty in the submitted form
$price = $request->price;
// when it gets to the server this is how this value looks like :
// $price in production server : null
// $price in development server : ''
}
When i try to save the object to a database like
Product::save($request->only('name', 'price'));
I get this error(only on production server)
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'price'
cannot be null
NOTE that the price column has 'default 0' on mysql table
Why is this happening?
UPDATE:
All this time i thought the request->input() method returned empty string('') if the field was not present. but just know i looked at the laravel source to see this :
public function input($key = null, $default = null)
{
$input = $this->getInputSource()->all() + $this->query->all();
return array_get($input, $key, $default);
}
here it returns null as the default value. then why am i getting empty string on development server?
This is happening because mysql inserts the default value if you don't define anything. In this case Laravel sends a value, which is null. You should not use Request::only, instead use an array.
It's always good to be specific, it makes your code readable and consistent.
Input Trimming & Normalization
By default, Laravel includes the TrimStrings and ConvertEmptyStringsToNull middleware in your application's global middleware stack. These middleware are listed in the stack by the App\Http\Kernel class. These middleware will automatically trim all incoming string fields on the request, as well as convert any empty string fields to null. This allows you to not have to worry about these normalization concerns in your routes and controllers.
If you would like to disable this behavior, you may remove the two middleware from your application's middleware stack by removing them from the $middleware property of your App\Http\Kernel class.
From: https://laravel.com/docs/5.4/requests#input-trimming-and-normalization

SilverStripe - Using the CheckboxsetField with MultiForm Module

I have a form using the multiform module. I have a checkboxsetfield populated by a dataobject.
When saving the form I am getting strange results. For instance if I select the first and third checkboxes then this is how the array appears in the database: 1{comma}3 when I expected to see 1,3
MyDataObject.php
<?php
...
if($SomeData = DataObject::get('SomeData')->sort('SortColumn'){
$fields->push( new CheckboxSetField('SomeData', 'Field Name', $SomeData->map('ID', 'Name')
));
}
MultiForm.php
<?php
...
public function finish($data, $form){
if(isset($_SESSION['FormInfo']['MultiForm']['errors'])){
unset($_SESSION['FormInfo']['Form']['errors']);
}
parent::finish($data, $form);
$steps = DataObject::get('MultiFormStep', "SessionID = {$this->session->ID}");
$MyStep = $this->getSavedStepByClass('MyStep');
if($this->getSavedStepByClass('MyStep')){
if($MyStep->loadData()){
$MyDataObject = new MyDataObject();
$MyStep->saveInto($MyDataObject);
$MyDataObject->write();
}
}
...
Any ideas how to process the array?
CheckboxSetField does have code which refers to {comma} when saving to the DB or when calling the dataValue function. This is essentially escaping any commas that were defined as values in the string when saving to a single column.
This tells me that either your multiform isn't providing the right input to CheckboxSetField or that there is more to this situation than your code is showing.
If CheckboxSetField gets an array like array('1,3'), that is when I would expect to see that type of result. Calling map like you have returns an SS_Map object which may not automatically convert the way you are expecting. Try adding ->toArray() after the map call when you are passing the values into the CheckboxSetField.
If that doesn't solve the issue, we probably will need to see the DataObject itself and a few other bits and pieces of information.

Categories