It looks like you can turn it into a Carbon instance with Carbon::createFromTimestamp($value). You'll probably have to play around with what $value looks like until you get something the method is expecting.
Merging Date and Timeslot into Carbon instance for laravel request
I am building a booking system form that has a input for the Date of booking using jQuerys datepicker ( expected output is 05/06/2015 ) and then a timeslot select box that has intervals of half an hour ranging from 9am to 11pm.
I have separated my question into multiple parts below,
-
Firstly I plan to store this in a booking_date column in my database, is this wise? Or would it be better off in two separate columns like the form?
-
If they should be merged into one how would I do this? Is it as simple as merging the two strings?
2b. Would I need to have the fields marked as fillable to be able to manipulate both of the inputs? ( My thinking here is that it gets removed from the input array rather than just not inserted into the query)
- Will this be able to be used by the date mutator? e.g
public function getDates()
{
return ['created_at', 'updated_at', 'booking_date'];
}
@beznez Where would that go? In the controller?
Wherever you need it to be, but probably in the controller. Something like:
$time = Input::only('time');
$date = Input:only('date');
$timestamp = \Carbon::createFromTimestamp($date . $time);
$booking = new \App\Booking;
$booking->booking_timestamp = $timestamp;
$booking->save();
return view('some-view', compact('timestamp'));
@beznez would both of the fields need to be in the fillable array in my request file? Or can I leave out time as date is the only field that is touching the database.
Depends on how you do it. If you want to mass-assign, then you'll need to add that to your fillable array:
$booking = \App\Booking::create($input);
Or you can leave it out and assign them manually, as I demonstrated above.
@beznez How would I use your suggestion in this example?
/**
* Store a newly created resource in storage.
*
* @return Response
*/
public function store(CreateBookingRequest $request, Booking $booking)
{
$booking->create($request->input());
}
Because I am referencing using CreateBookingRequest $request if I used Input::only('time'); would it be counter productive as that data hasn't passed through the validation?
Basically you make the timestamp and add it the the input to be mass-assigned. Make sure $fillable is updated.
/**
* Store a newly created resource in storage.
*
* @return Response
*/
public function store(CreateBookingRequest $request, Booking $booking)
{
$input = $request->all();
$input['timestamp'] = Carbon::createFromTimestamp($input['date'] . $input['time']);
$booking->create($input);
}
@beznez I tried that but I receive this error A non well formed numeric value encountered But it disappeared after I added :00 to the input as I think Carbon needs a time format such as 09:30:00.
Even with the above changes my database field still shows 0000-00-00 00:00:00.
I renamed my field from date to something more sensible booking_for and still no luck. What's strange is if I use dd($input); I see the carbon instance in my array? Yet it is not added into my database.
P.S I also had to add strtotime() to the code for it to become a timestamp for Carbon. Here is the edited code.
public function store(CreateBookingRequest $request, Booking $booking)
{
$input = $request->all();
$input['timestamp'] = Carbon::createFromTimestamp(strtotime($input['date'] . $input['time'] . ":00"));
//dd($input);
$booking->create($input);
}
Yes, you should see the carbon instance in your array. That's one of the really cool things about carbon. Inspect that and if it's not right, mess with the object until you give it what it wants. I don't happen to recall with Carbon. There should also be a __toString() method that you might need to call. With things I'm not familiar with or don't use that often, I usually dd($whateverImInterestedIn); until I get what I want and then move forward.
@beznez Yeah I have the array but its not saving to my database? Even with the above changes my database field still shows 0000-00-00 00:00:00.
EDIT::
After rewatching this tutorial
https://laracasts.com/series/laravel-5-fundamentals/episodes/11
Is this field best set in the Model file rather than in the controller?
Can you post the dump of your Carbon instance?
"date" => Carbon {#172 ▼
+"date": "2015-05-12 15:30:00.000000"
+"timezone_type": 3
+"timezone": "UTC"
}
I was actually going to suggest that. If you add a mutator to set the timestamp that is a good idea, but you'll still have to stick the timestamp together before hand. So if you just add in the method, that should be it. Make sure to use the proper name conventions that Laravel is expecting as Mr. Way explained in that video.
I have changed my code to this
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Booking extends Model {
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'bookings';
protected $fillable = [
'first_name',
'last_name',
'company_id',
'booking_for'
];
public function setBookingForAttribute($date)
{
$this->attributes['booking_for'] = Carbon::now();
}
public function setFirstNameAttribute($first_name){
$this->attributes['first_name'] = "Testing";
}
}
The first name changes, but the date doesn't.
EDIT::
I changed the bokoing_for field to varchar and I was able to set its value using $input['booking_for'] = "testing"; so it must be something to do with the database not liking how Carbon is outputting the date.
That's odd. That should've worked. You probably want something like this:
public function setBookingForAttribute($date, $time)
{
$this->attributes['booking_for'] = Carbon::createFromTimestamp(strtotime($date . $time . ":00"));
}
But Carbon::now() should have worked.
With that code I receive this error.
Missing argument 2 for App\Booking::setBookingForAttribute()
Even though in my Input array I have this...
"booking_for" => "05/21/2015"
"time" => "09:00"
EDIT::
I also have just tried this.
public function setBookingForAttribute($date)
{
$this->attributes['booking_for'] = Carbon::createFromTimestamp(strtotime($date . $this->attributes['time'] . ":00"));
}
But I get this error Undefined index: time
Although the field gets correctly inputted if I do this
public function setBookingForAttribute($date, $time = "12:34")
{
$this->attributes['booking_for'] = Carbon::createFromTimestamp(strtotime($date . $time . ":00"));
}
RE: With that code I receive this error.
Missing argument 2 for App\Booking::setBookingForAttribute()
Even though in my Input array I have this...
I have exactly the same issue.
My form contains two inputs date and time.
Within the database there is a database column titled date.
I want to use mutators to set the date field in the database to be a concatenation of both the date and time inputs.
For some reason, the request is passing a NULL for the time input, hence why I get the same error as HarryKe
After a few hours I think I have finally sorted this. I will share my findings in the hope that it assists someone.
1: I have a requirement to record an event's Date and Time. Thinking from the bottom up, it makes complete sense to me to have a single timestamp field in the database. This will make any future SQL comparisons simpler that have a separate date and time field.
So, in my form I have two separate inputs
<div class='form-group'>
{!! Form::label('showdate', 'Show Date:') !!}
{!! Form::date('showdate', Carbon\Carbon::now()->format('Y-m-d'),
[
'class' => 'form-control input-sm',
'placeholder' => 'Enter the show date'
]
)
!!}
</div>
<div class='form-group'>
{!! Form::label('showtime', 'Show Time:') !!}
{!! Form::time('showtime', Carbon\Carbon::now()->format('H:i'),
[
'class' => 'form-control input-sm',
'placeholder' => 'Enter the show time'
]
)
!!}
</div>
In my model I've added showdate and showtime so they are mass assiginable
protected $fillable = ['description','cost','showdate','showtime'];
Now, I know that I could add a protected array called $dates and add showdate and showtime to this. This would cause Laravel to automatically create Carbon instances.
The problem with doing this, is that as soon as you define your dates as above - Laravel no longer reads any related mutators you add.
So, I had to create my own get mutator. If anything now requests showdate, I simply return it in a Carbon instances (and this can either be manipulated or formatted at the view level etc)
public function getShowDateAttribute()
{
if (isset($this->attributes['showdate'])) {
return Carbon::createFromTimestamp(strtotime($this->attributes['showdate']));
}
else
{
return Carbon::Now();
}
}
I have two additional setter mutators so the date and time can be set seperately
public function setShowDateAttribute($showdate)
{
$timepart = $this->showdate->format('H:i');
$this->attributes['showdate'] = Carbon::createFromTimestamp(strtotime($showdate.$timepart ));
}
public function setShowTimeAttribute($showtime)
{
$datepart = $this->showdate->format('Y-m-d'); //Get just the date section of the showdate field
$this->attributes['showdate'] = Carbon::createFromTimestamp(strtotime( $datepart.$showtime));
}
This seems to work.
Any obvious problems doing it like this?
Other than your formats are reversed for date and time. No. Of course the format issues are kinda important. Databases can handle Date timestamps very easily in one field.
Please or to participate in this conversation.