Laravel 8: issues with dateTime (DataTables & Charts) - laravel

This issue is happening across the entire application...
I have datatables & charts:
Datatables don't sort by dateTime correctly, aka Started Column.
Charts always starts with the latest date...not by order:
I am using Carbon for datatables like this:
->editColumn('startDateTime', function ($report) {
return Carbon::parse($report->startDateTime)->format('d M, Y');
})
For the charts, returning data as json then format the date:
$data = TrafficViolation::select('id', 'violationDateTime')
->orderBy('violationDateTime')
->get()
->groupBy(function($data) {
return Carbon::parse($data['violationDateTime'])->format('M');
});
The column type of these dates are DateTime in the database.
What's frustrating is that there is a datatable called Audit Log that came with the theme (Metronic 8) and it's sorting the date correctly here (created at):
And looking to its controller:
->editColumn('created_at', function (Activity $model) {
return $model->created_at->format('d M, Y H:i:s');
})
Looking at the Model there isn't anything related to Carbon or date functions there, noting that the data type of created_at is timestamp.
I tried:
Changing data type to timestamp instead of datetime.
Copying the same code of audit log, no need for Carbon, I get an error format() unknown.

To me it looks like you are overcomplicating things, why don't you just sortByDesc if you need the newest results first I do not understand. You can do this like so:
First in you TrafficValidation model add a casts to datetime
protected $casts = [
'violationDateTime' => 'datetime',
];
Then where you return the query just do
$data = TrafficViolation::select('id', 'violationDateTime')
->orderByDesc('violationDateTime')
->get()
->groupBy(function($data) {
return Carbon::parse($data->violationDateTime)->format('M');
});
And the reason audit log works for sorting is because it by default doesnt look at all at your query sorting, it takes the data and sorts it by itself

Related

Laravel Scout/Meilisearch - filter by a non-searchable column

I want to make it so that I can filter results based on a column that isn't searchable with Meilisearch and Laravel scout.
So imagine a "Comment" table, with the following searchable columns:
public function toSearchableArray() {
$array = Arr::only(
$this->toArray(),
['id','title', 'link', 'raw_text', 'subchan', 'nsfw']
);
return $array;
}
But only get results past a certain date:
Comment::search($query, ['filters' => 'created_at > 795484800'])
To do this, I need to add created_at scout's toSearchableArray. The problem with this is that when a user searches, results from created_at will also be queried.
If I understand you correctly you want to be able to filter based on the created_at column, but it shouldn't be searchable, ie entering "795" as a query shouldn't return all results where "795" is part of the timestamp?
I don't think Scout will allow you to achieve this in a simple way at the moment but it should still be possible.
Step 1 is to add the created_at column to the toSearchableArray() method. This will ensure the data is indexed by Meili.
Step 2 is to alter the configuration of the index where your model is searchable in order to exclude created_at from the list of searchable attributes. This is psuedo code and undocumented but it should look something like this:
$dummy = new Comment();
// Should resolve to an engine: https://github.com/laravel/scout/blob/f8aa3c3182fe97f56a6436fd0b28fcacfcbabc11/src/Searchable.php#L279
$engine = $dummy->searchableUsing();
// Should resolve to MeiliSearch\Endpoints\Indexes via a magic method that resolves the underlying Meili driver:
// https://github.com/laravel/scout/blob/33bbff0e3bfb1abd0ea34236c331fc17cdeac0bc/src/Engines/MeiliSearchEngine.php#L298
// ->
// https://github.com/meilisearch/meilisearch-php/blob/f25ee49b658f407af3d3f1f9a402997e7974b6bb/src/Delegates/HandlesIndex.php#L23
$index = $engine->index($dummy->searchableAs());
// https://github.com/meilisearch/meilisearch-php/blob/f25ee49b658f407af3d3f1f9a402997e7974b6bb/src/Endpoints/Delegates/HandlesSettings.php#L55
$index->updateSearchableAttributes(
['id','title', 'link', 'raw_text', 'subchan', 'nsfw']
);
Once created_at is indexed but not searchable you want to filter on the value. Meili has operators for numeric values.
Step 3 is to do a custom search using Scout:
Comment::search($query, function (Indexes $meilisearch, $query, $options) {
$options['filters'] = 'created_at>795484800';
return $meilisearch->search($query, $options);
});
Again, this is pseudo code – I haven't tested any part of it. I would really appreciate if Scout would implement support for customizing the index' settings on creation or exposing a method for updating the settings, allowing you to add driver specific settings in your configuration file for example.
i spent numerous hours debugging and getting the filter for dates to work.
this wont work as the where clause only accepts two arguments
Comment::search($query)->where('created_at', '>', 795484800)->get();
this also wont work because the arguments passed are not part of the two options that they have supported in the scout library
Comment::search($query, function (Indexes $meilisearch, $query, $options) {
$options['filters'] = 'created_at>795484800';
return $meilisearch->search($query, $options);
});
my solution for everyone out there trying to get this to work is to use the following:
$results = Event::search(
query: $request->get('query'),
callback: function (Indexes $meilisearch, $query, array $options) use ($request, $from, $to) {
$options['filter'] = "from <= 1667692800";
// dd($options);
return $meilisearch->rawSearch(
$query,
$options,
);
},
)->paginate();
hope this helps anyone else having issues as this wasted my morning searching for solutions until i decided to dig into the code in the library.
I solved my problem by using filterable attributes of Meilisearch. But it needs to be configured before running the search. I used php artisan tinker to solve this as follows, you might want to write an artisan command to do so.
$client = new MeiliSearch\Client('https://url_to_meilisearch_instance:7700');
$client->index('comments_index')->updateFilterableAttributes(['created_at']); // Replace your index_name
And that's about it. If you have a rather large dataset, you might want to run the following command to check the status:
$client->index('comments_index')->stats();
If the response contains isIndexing => false you're good to go. Now you may run the filter as usual,
Comment::search($query)->where('created_at', '>', 795484800)->get();

Wrong timezone with Eloquent Model timestamps on $model->get(), but correct with print_r()

I am experiencing something quite weird for any Eloquent Model with Laravel 7!
P.S.: I've run on every test I did:
php artisan optimize:clear
I don't know what I am missing here!
I won't post any code because that's a simple CRUD with Model Bindings.
When saving the created_at and updated_at fields, it is correctly saved in the MySQL with my timezome "America/Sao_Paulo".
But if I do this in any controler:
return $model->get()
or
return $model->paginate()
or
Model::all()
I get the response:
{
"data": [
{
... other fields
"created_at": "2020-08-23T15:22:41.000000Z",
"updated_at": "2020-08-23T15:22:41.000000Z"
}
]
}
And it returns the wrong time with +1 hour.
However, here is where things get weird... if I print_r() any of them, I get the corret time!
Array
(
... other fields
[created_at] => 2020-08-23 12:22:41
[updated_at] => 2020-08-23 12:22:41
)
I tried to use:
public function getDateFormat()
{
return 'Y-m-d H:i:s';
}
But no effect!
Thanks in Advance!
Laravel 7 uses a new date serialization format when using the toArray or toJson method on Eloquent models with UTC
Before Laravel 7, dates would be serialized to a format like the following :
2019-12-02 20:01:00
Dates serialized using the ISO-8601 format will appear like :
2019-12-02T20:01:00.283041Z
Please note that ISO-8601 dates are always expressed in UTC.
If you would like to keep using the previous behavior you can override the serializeDate() method on your model :
use DateTimeInterface;
protected function serializeDate(DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
See the official upgrade doc here
If you have changed the timezone config in config/app.php but saving the date in the database with other timezone formats then keep the timezone to UTC so laravel doesn't change it to other formats when calling it from model class, or you can do the opposite by saving it by UTC format in database then change the config to a timezone that your app needs.
// config/app.php
'timezone' => 'UTC',

Time format of database field, help needed

Time is stored in my database as H:i:s format for a timefield.
When I query I want time returned as hours:minutes without the seconds part.
I tried to set the "protected $dateFormat " setting using a Mutator. Can anyone show an example of the dateFormat setting needed? The database must remain hour:minute:seconds time settings, only the retrieved value needs to be changed for display.
protected $dateFormat = 'Y-m-d H:i:s'; // ?
One way to solve it is to treat dates as Carbon instances. The format to save on database will be auto-converted and you should use in any format.
protected $dates = [
'field_name'
];
https://laravel.com/docs/5.8/eloquent-mutators#date-mutators
// converting db column name time_match into the function as getTimeMatchAttribute worked for me.
public function getTimeMatchAttribute($value){
return date('H:i',strtotime($value));
}
you can make it with getters function in your model
like this:
public function getTimeAttribute($time){
return date('h:i',strtotime($time))
}
Time in function name should be your column name in upper case

Fullcalendar query with different column

on my models to load data is
public function getgl()
{
$this->db->select('trID id, purpose title, date start');
$this->db->from('trroom');
return $this->db->get()->result();
}
and my controller is
$data=$this->Reservationmodel->getgl();
echo json_encode($data);
with this code is no problem for me but the problem come when i want to add not only the date but i want to input a date time but from my database date and time is a diffrent column, can any one help me for this problem?
Just concatenate the two fields date and time. If you have MariaDB/MySQL it would be something like this in your model:
public function getgl()
{
$this->db->select('trID id, purpose title, date start, CONCAT(date," ",timecolumn) AS datetimecolumn');
$this->db->from('trroom');
return $this->db->get()->result();
}
You can use the MySQL function DATE_FORMAT() if you want more diplay options: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format

Convert timestamp to date in Laravel?

How can I return from the database all rows with a timestamp converted to a date (d-m-Y H:i), using the all() method?
It's not created_at or updated_at column, it's custom attribute, call it birthday if you wish.
timestamp columns like created_at are being parsed first. the U is simply the timestamp format. you can return your own format. for other formats see date docs.
edit: as stated in my comment, getDateFormat() is for both ways (insert, selects). your best bet would be using format inside the model. example:
public function getMyBirthdayAttribute()
{
return $this->my_birthday->format('d.m.Y');
}
use $model->my_birthday to call the attribute.
// controller
$posts = Post::all();
// within sometemplate.blade.php
#foreach($posts as $post)
my formatted date: {{ $post->my_birthday }}
#endforeach
The better way to manage dates with Laravel IMHO is to use the getDates accessor that is build into Laravel.
All you need to do is to set a method on your Model as such.
public function getDates()
{
return [
'my_birthday',
'created_at',
'updated_at',
];
}
This will return a Carbon object. Carbon is insanely awesome for manipulating dates.
It is what Laravel does by default to created_at and updated_at.
You can then do things like:
$my_birthday->diffForHumans() // 2 Days ago
$my_birthday->format('d.m.Y') // 20.02.1979
There are tons of helpers here for you. Check out the Carbon docs: https://github.com/briannesbitt/Carbon
Definitely worth learning. It might not be easy to understand for a beginner. However, I would advise you take a look and get your head around it. It will change your life - Dates can be a pain!
In this case, you need to convert the date within the query, if mysql is being used as your database then you may use a raw query like this:
// Assumed my_birthday is like 1255033470
$raw = DB::raw("date_format(from_unixtime(my_birthday),'%b %d, %Y %l:%i %p') as dob");
$result = Model::get(array('id', 'username', $raw));
You may write it within single line:
$result = Model::get(array('id', 'username', DB::raw("...")));
Just place this on your code
$post it depend on what you create
$post ->created_at->format('d.m.Y')

Resources