LARAVEL 5 How to store empty DateTime input to Null value instead of 0000:00:00 00:00 value - laravel-5

i had two input Datetime field.
User can choose to fill in either these two field.
For the empty input Datetime field, i want it to store as Null value in Database.
But currently the empty input Datetime field is store as 0000:00:00 00:00 value in Database. What code should i modified?

you can use model observers to unset the attribute before saving when it is empty. But be sure that the fields are nullable
class Flight extends Model
{
public static function boot()
{
parent::boot();
self::saving(function ($flight_model) {
if(empty($flight_model->arriveDateTime)) unset($your_model->attributes['your_date_field1'];
if(empty($flight_model->departDateTime)) unset($your_model->attributes['your_date_field2'];
});
}
}
this discussion would be a good reference
Update
to do the limitation in the controller you'll use required_without_all:foo,bar,... which as described in doc.s
The field under validation must be present and not empty only when all of the other specified fields are not present
to use it we'll add new rules like
$rules = array(
'arriveDateTime' => 'required_without_all:departDateTime',
'departDateTime' => 'required_without_all:arriveDateTime',
);
$validator = Validator::make(Input::all(), $rules);
and if you're using rules already just append this two roles to them. that's for the controller validation part.
for the view part I'll assume you've two inputs with id="arriveDateTime" and id="departDateTime" the code would be like
$(function() {
<!-- if the first input value changed disable the second input -->
$('#arriveDateTime').on('change', function() {
if ($(this).val() == '') {
$('#departDateTime').prop("disabled", false);
} else {
$('#departDateTime').prop("disabled", true);
}
});
<!-- if the second input value changed disable the first input -->
$('#departDateTime').on('change', function() {
if ($(this).val() == '') {
$('#arriveDateTime').prop("disabled", false);
} else {
$('#arriveDateTime').prop("disabled", true);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<input type="text" id="arriveDateTime" />
<input type="text" id="departDateTime" />

All you need is Eloquent Mutators.
Below a simplified example, basically from https://laravel.com/docs/5.4/eloquent-mutators#defining-a-mutator
class User extends Model
{
/* Set or mutate value of property */
public function setDateInputAttribute($value)
{
$this->attributes['date_input'] = $this->dateTimeOrNull($value);
}
/* This method should get another place, because it's not the core of this model */
private function dateTimeOrNull($value)
{
/*
Check if given datetime is valid. Yes? Return original $value
For simplicity, I use PHP's DateTime class
*/
if (DateTime::createFromFormat('Y-m-d H:i:s', $value) !== false) {
return $value;
}
/* Datetime is not valid. Return null */
return null;
}
}
Further
I suppose your datetime format is like yyyy-mm-dd hh:ii:ss

You can uses laravel mutators. Here's one for date of birth.
public function setDob($value)
{
$this->attributes['dob'] = strlen($value)? Carbon::createFromFormat('d/m/Y', $value) : null;
}

Related

Laravel Mutators and Accessors

I have created mutator date function in model to convert the created_at date into human readable time using diffForHumans().
I have done the following
public function setDateAttribute($value){
return \Carbon\Carbon::parse($value)->diffForHumans();
}
It works fine but it affects in all. it is possible to apply this mutator only on the specified function of the controller rather than all function
A small logic in the mutator would do the job:-
public function setDateAttribute($value){
if ( request()->path() === "/yourURL/To/IndexMethod"){
return $this->attributes['date'] = \Carbon\Carbon::parse($value)->diffForHumans();
} else {
return $this->attributes['date'] = $value;
}
}
the idea is to check by the url.
getting request path helper
EDIT
Comparison using route name is better, as exact path can contain id/slugs.
public function setDateAttribute($value){
if ( \Route::currentRouteName() === "/yourRouteName/To/IndexMethod"){
return $this->attributes['date'] = \Carbon\Carbon::parse($value)->diffForHumans();
} else {
return $this->attributes['date'] = $value;
}
}
getting route name

Laravel set a common validator for all date fields in the system

I have different date fields in different models, I need to validate these date fields format on save of each model accordingly. is this possible?
Of course, you can. You just need to add this code below to your Model.
public static $rules = [
'date'=> 'reqired|date_format:MM:dd:YYYY' //if date is not required, ommite it
]
You can use different formats for your date in your different Models like MM:dd etc. Hope this helps you.
EDIT
To be able to use multiple date formats in a single validator You can define the multi-format date validation in your AppServiceProvider with the following code:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::extend('date_multi_format', function($attribute, $value, $formats) {
// iterate through all formats
foreach($formats as $format) {
// parse date with current format
$parsed = date_parse_from_format($format, $value);
// if value matches given format return true=validation succeeded
if ($parsed['error_count'] === 0 && $parsed['warning_count'] === 0) {
return true;
}
}
// value did not match any of the provided formats, so return false=validation failed
return false;
});
}
}
You can later use this new validation rule like that:
'date' => 'date_multi_format:"Y-m-d H:i:s.u","Y-m-d"' //or any other format
Hope this helps, thanks.

Modify all attributes of a Laravel model

Accessors will do their job on a single attribute perfectly, but I need a way to have a method to do an Accessor/Getter job on all attributes and automatically.
The purpose is that I want to replace some characters/numbers on getting attributes and then printing them out. I can do it from within controller and manually but I think it would be great to have it from model side and automatically.
Like overriding getAttributes() method:
public function getAttributes()
{
foreach ($this->attributes as $key => $value) {
$this->attributes[$key] = str_replace([...], [...], $value);
}
return $this->attributes;
}
But I have to call it every time on model $model->getAttributes();
Any way to do it automatically and DRY?
Try something like:
public function getAttribute($key)
{
if (array_key_exists($key, $this->attributes) || $this->hasGetMutator($key)) {
if($key === 'name') return 'modify this value';
return $this->getAttributeValue($key);
}
return $this->getRelationValue($key);
}
It's fully overriding the default method so be a bit careful.
EDIT
Also check out: http://laravel.com/docs/5.1/eloquent-mutators
I would go with following approach and override the models __get method:
public function __get($key)
{
$excluded = [
// here you should add primary or foreign keys and other values,
// that should not be touched.
// $alternatively define an $included array to whitelist values
'foreignkey',
];
// if mutator is defined for an attribute it has precedence.
if(array_key_exists($key, $this->attributes)
&& ! $this->hasGetMutator($key) && ! in_array($key, $excluded)) {
return "modified string";
}
// let everything else handle the Model class itself
return parent::__get($key);
}
}
How about running it with each Creating and Updating events. So you can do something like that:
public function boot()
{
Model::creating(function ($model)
return $model->getAttributes(); //or $this->getAttributes()
});
Model::updating(function ($model)
return $model->getAttributes(); //or $this->getAttributes()
});
}

Validation: how to set a field that is not required to 'null' when input is empty

I have a validation rule that looks like this:
$rules = ['target' => 'numeric'];
It's not a required field. If a value is not specified in the input (i.e. Input::get('target') == ''), I want the field to be set to NULL in the database.
Currently the above rule passes, and in the absence of a numeric input, it gets set to 0 in the database.
What's the best solution?
You can set field as null in Laravel simply by assigning null value to the appropriate model attribute before calling save().
if(! Input::get('target') ){
$eloquent_model->target = null;
}
$eloquent_model->save();
But if you want to insert null values in more than one model, you can create base model and inherit it by all other models.
class BaseModel extends Eloquent {
public static function boot()
{
parent::boot();
static::creating(function($model) {
static::setNullWhenEmpty($model);
return true;
});
}
private static function setNullWhenEmpty($model)
{
foreach ($model->toArray() as $name => $value) {
if (empty($value)) {
$model->{$name} = null;
}
}
}
}
Now all empty fields will be set to null automatically and you don't have to check before save.
Reference.
In this case i like to use mutators :
public function setTargetAttribute($target){
$this->attributes['target'] = $target ?: null;
}
I don't think it's an issue of laravel, you must add tag mysql...
Alter the table to add Null as default value.. Currently if you pass blank value, it'll add 0 because by default it is not NULL and shows
Warning: #1366 Incorrect integer value: '' for column 'target' at row 1.
Here is the query to alter..
ALTER TABLE `table` CHANGE `target` `target` INT( 11 ) NULL
After running above query, target will accept NULL value instead of 0!!
My solution was this (Laravel 5.2):
//Model.php
public function nullIfBlank($field) {
return trim($field) !== '' ? $field : null;
}
// your custom model that extends Model.php
public function setTargetAttribute($target) {
$this->attributes['target'] = $this->nullIfBlank($target);
}
Pay attention to naming your setter (mutator) exactly as above, lowerCamelCase and magic will happen.

check if dates are not within range before saving in yii

how can i check if the dates posted in user's form exist in a range before saving? It's suppose to check different scenario date ranges. Below is just one of them. If it doesn't fall into range, it then posts.
is there a better way to do this?
$model = Table::model();
$criteria = new CDbCriteria;
//this is where i don't know how to get the values ($start,$end) from user before posting
$criteria->addCondition('start_date < '.$start);
$criteria->addCondition('end_date > '.$end);
You have to create custom validation function :
In rules add : this rules will work for both insert and update.
public function rules()
{
return array(
array('dateField', 'myCheckdate',),
);
}
In your custom validation function , you can apply your code to check the date range
public function myCheckdate($attribute,$params)
{
if(!$this->hasErrors())
{
if(Condition == false) // place your condition here
{
$this->addError($attribute,'The date is incorrect.');
}
}
}

Resources