Save date into database with Carbon - php

I'm still new in Laravel. Currently, I'm learning and working on Carbon. I already looking on every documentation and other solution but I still don't get it. I hope there is someone can teach and show me step by step how to correct or improve my code.
ComplaintController.php
public function store(Request $request)
{
if (count($request->defect_id) > 0) {
foreach($request->defect_id as $item=>$v) {
$data = array(
'defect_id' => $request->defect_id[$item],
'image' => $filename,
'description' => $request->description[$item],
'report_by' => Auth::user()->id,
'created_at' => Carbon::today()->toDateString(),
'updated_at' => Carbon::now()->toDateTimeString()
);
Complaint::insert($data);
I'm saving created_at field as date only, no time and it is in the format of (yy-mm-dd).
index.blade.php
<div class="panel-body">
<table class="table table-hover">
<thead>
<tr>
<th>Defect Name</th>
<th>Description</th>
<th>Image</th>
<th>Report Date</th>
<th>Due Date</th>
</tr>
</thead>
#foreach($complaint as $c)
<tr>
<td>{{$c->defect->name}}</td>
<td>{{$c->description}}</td>
<td><img src="{{ Storage::url('complaint/' . $c->image)}}" class="" alt="{{$c->image}}"></td>
<td>{{$c->created_at->toDateString()}}</td>
<td></td>
</tr>
#endforeach
</table>
</div>
My date is still showing finely in the table as (yy-mm-dd) but I want the date to be in format of (dd/mm/yy) so I try to use this kind of code {{$c->created_at->toDateString()->format("dd/mm/yy")}} and there is error appeared which is Call to a member function format() on string. Later on, I need to add another field for duedate and use this function addDays(30). So, what I need to do? I'm guessing that I need to put another function in my model but I can't figure out how to do it.

As mentioned by #Tim Lewis as well,
replace
{{ $c->created_at->toDateString()->format("dd/mm/yy") }}
to
{{ $c->created_at->format("dd/mm/yy") }}
As toDateString() converts it to string before changing the format.
You can also try using standard php format for datetime, instead of Carbon class,
{{ date("d/m/Y", strtotime($c->created_at)) }}
As for your second question of you want to add new table data column ,
<tr>
<td>{{ $c->defect->name }}</td>
<td>{{ $c->description }}</td>
<td><img src="{{ Storage::url('complaint/' . $c->image)}}" class="" alt="{{$c->image}}"></td>
<td>{{ $c->created_at->format("dd/mm/yy") }}</td>
<td>{{ $c->created_at->addDays(30) }}</td>
</tr>

This should work...
To save the date in the format dd/mm/yy, I would use the following:
date('d-m-Y', strtotime(Carbon\Carbon::now()))
To reformat the date in a view, I would use:
date('d-m-Y', strtotime($c->created_at))
I prefer to use the base php functions wherever possible to keep things simple.
If someone knows a reason not to, please let me know.
As for the adding of days,
date('d-m-Y', strtotime($c->created_at) + (60 * 60 * 24 * 30))
Should work.
Most date related problems can be solved with strtotime(), its very useful. Be sure to read up on it here: https://www.php.net/manual/en/function.strtotime.php

Casted date fields:
In Laravel the created_at and updated_at fields are casted as date fields already. So you don't have to transform this into date formats.
You can simply do
<td>{{ $c->created_at->format("d/m/y") }}</td>
Fields created_at and updated_at are also automatically filled
So you don't need to fill this fields
You can simply do
$data = array(
'defect_id' => $request->defect_id[$item],
'image' => $filename,
'description' => $request->description[$item],
'report_by' => Auth::user()->id,
);
Complaint::create($data);
Extra date field duedate
When you add custom date fields you need to cast them in the model to be date.
Add this in you model:
protected $dates = ['duedate'];

Related

Conditional formatting in Laravel

I am new to Laravel, I am trying to format table cells as red if the current date - row date =3 months
this is how I did it: in controller
public function get_rxs()
{
$ldate = Time();
$rxs = rxs::all();
return view('viewlog', [
'rxs' => $rxs,
'ldate' => $ldate
]);
in view:
#foreach($rxs as $rx)
<tr #if($ldate-$rx->rxdate>="7776000") class="table-danger" #else #endif >
<td>{{ $rx->id }}</td>
<td>{{ $rx->pt_name }} <br></td>
<td>{{ $rx->dr_name }}</td>
<td>{{ date("Y-m-d",$rx->rxdate) }}</td>
and i got the time saved as integer (epoch) the thing is it is calculating sec:min:hr and i really do not want to include that in the calculation since it may make it a split second difference between red formatting and regular and i want it to always use 00:00:00 time and whatever date it is.. how to do that.. I tried doing it with date() but it says invalid numerical data since i think date returns chars with numbers..
Change
<tr #if($ldate-$rx->rxdate>="7776000") class="table-danger" #else #endif >
to
<tr class="{{ ($ldate->$rx->rxdate >= "7776000") ? 'table-danger' : ''}}">
I simply used carbon dependencies and it worked like a charm
Like this:
1. added use Carbon\Carbon; in the controller
2. Channged $ldate to this $ldate = Carbon::now()
3. in the view I added this after foreach
<tr class="#if($ldate->diffindays($rx->rxdate)>="90") table-danger #elseif($ldate->diffindays($rx->rxdate)>="60") table-warning #endif" >>
and it started showing difference in days only
So I stopped using epoch format and used DateTime format instead

Laravel & PHP: Cannot reach array items without a trick, why is that?

Introduction to the problem
I have written a class to import a specific CSV file. This class handles everything except moving and reading the imported file. This is done in the controller by using de File facade in Laravel.
The description below only describes one of the arrays, but I use more arrays, and also in the class itself I get the same problem. The problem is that the app crashes with some obscure error everytime I try to access an item in the array by using a string as key value. I tested this in a seperate, non-laravel, php-file and there I don't get an error. It's only in my Laravel app. Strange thing is that I tested the arrays the following way:
a) using array_key_exists - No keys are found (I used both ' and ")
b) using array_keys - This time I get all the keys from the array
c) for example: $report['student_number'] - Doesn't work, I get an error here
d) for example: $report[array_keys($report)[0]] - This works
e) In vanilla PHP I do the same and there I do not get any errors.
The real code
In the controller I handle the upload the following way:
$uploaded_file = $request->file('uploadfile');
$uploaded_file->move(storage_path().'/files', $uploaded_file->getClientOriginalName());
$import_file = storage_path().'/files/'.$uploaded_file->getClientOriginalName();
if(File::exists($import_file) && File::isReadable($import_file)) {
$raw_file_data = File::get($import_file);
$import = ImportStudents::getInstance();
$import_result = $import->import($raw_file_data);
}
In the Import class I have a private property:
private $report = [];
I fill the array with data the following way:
$this->report[$student_number][] = [
'field' => $field,
'db_field' => 'student_number',
'new_value' => $value,
'old_value' => $student_number,
'action' => 'updated'
];
In the class I finaly return this array to the controller:
return $this->report;
In the controller I pass this array to the view:
return view('home.import_report')->with('report', $import_result);
In the blade file I use the following code:
#foreach($report as $report_row)
<td>{{ $report_row['field'] }}</td>
<td>{{ $report_row['db_field'] }}</td>
<td>{{ $report_row['new_value'] }}</td>
<td>{{ $report_row['old_value'] }}</td>
<td>{{ $report_row['action'] }}</td>
#endforeach
The error
The "C:\Windows\Temp\php57CD.tmp" file does not exist or is not
readable.
Remarks
Above is only one part in my code where I get the error. As I mentioned before, I also get the same error in the code of the class.
Specifications
Laravel: 6.x
PHP: 7.3.10
Question
What am I overlooking here? What is the problem?
The solution for the above mentioned problem with showing the report, how could I forget, that I needed an extra foreach loop.
Old code
#foreach($report as $report_row)
<td>{{ $report_row['field'] }}</td>
<td>{{ $report_row['db_field'] }}</td>
<td>{{ $report_row['new_value'] }}</td>
<td>{{ $report_row['old_value'] }}</td>
<td>{{ $report_row['action'] }}</td>
#endforeach
The answer was so obvious already in my own code :-(, this code:
$this->report[$student_number][] = [
'field' => $field,
'db_field' => 'student_number',
'new_value' => $value,
'old_value' => $student_number,
'action' => 'updated'
];
New code (solution)
#forelse($report as $student_number => $report_row)
<tr><td colspan="6" style="color: white; background-color: darkblue; padding: 0;"><h5>{{ $student_number }} - {{ $report_row[0]['name'] }}</h5></td></tr>
#foreach($report_row as $actions)
<tr>
<td></td>
<td>{{ $actions['field'] }}</td>
<td>{{ $actions['db_field'] }}</td>
<td>{{ $actions['new_value'] }}</td>
<td>{{ $actions['old_value'] }}</td>
<td>{{ $actions['action'] }}</td>
</tr>
#endforeach
#empty
<tr><td colspan="6">No changes</td></tr>
#endforelse
But this problem still exists with arrays
a) using array_key_exists - No keys are found (I used both ' and ")
b) using array_keys - This time I get all the keys from the array
c) for example: $report['student_number'] - Doesn't work, I get an error here
d) for example: $report[array_keys($report)[0]] - This works
e) In vanilla PHP I do the same and there I do not get any errors.
What's not working
$student->first_name = $imported_row['Roepnaam'];
But the key 'Roepnaam' does exist in the array.
With array_keys($imported_row) I can see that the key exists.
What is working
$student->first_name = $imported_row[array_keys($imported_row)[1]];
This what puzzles me!

Laravel collection turns empty inside foreach loops

I have 3 collections on different items that I need to show and group by date, in the blade file I loop over the dates to show these collections, but for some reason whatever the first collection is, something wrong happens with it, it shouldn't change based on the date, let's say I have two dates (2019-03, 2019-01), I end up with two different instances of the same collection, one with the data, and one without(an empty collection), even though I am calling the same variable.
The controller method:
public function index()
{
//Retrieving the Models.
$invoices_egp = auth()->user()->invoices()->where('paid', 1)->where('currency', 'EGP');
$invoices_usd = auth()->user()->invoices()->where('paid', 1)->where('currency', 'USD');
$orders = \App\Order::where('vendor_id', auth()->user()->id)->where('paid', 1);
//Getting the different dates of these Models.
$egp_invoices_dates = $invoices_egp->get()->map(function ($invoice) {
return Carbon::parse($invoice->created_at)->format('Y-m');
});
$usd_invoices_dates = $invoices_usd->get()->map(function ($invoice) {
return Carbon::parse($invoice->created_at)->format('Y-m');
});
$orders_dates = $orders->get()->map(function ($order) {
return Carbon::parse($order->created_at)->format('Y-m');
});
//Getting the unique dates.
$dates = $orders_dates->merge($usd_invoices_dates)->merge($egp_invoices_dates)->unique();
return view('dashboard.vendor.reports.index', compact('invoices_egp', 'invoices_usd', 'orders', 'dates'));
}
The relevant part of the blade file:
<div class="col-lg-12">
#if ( count( $dates ) )
#foreach($dates as $date)
<div class="card-box">
<div class="table-responsive">
<table class="table table-actions-bar m-b-0">
<thead>
<tr>
<th>
Month
</th>
</tr>
<tr>
<td>
{{ $date }}
</td>
</tr>
</thead>
<tbody>
<tr>
<th colspan="100%">Type</th>
<th>Total</th>
</tr>
<tr>
#if(count($invoices_egp->get()))
<td colspan="100%">Invoice in EGP</td>
<td>{{ $invoices_egp->whereYear('paid_at', \Carbon\Carbon::parse($date)->year)->whereMonth('paid_at', \Carbon\Carbon::parse($date)->month)->sum('total') }}</td>
#endif
</tr>
<tr>
#if(count($invoices_usd->get()))
<td colspan="100%">Invoice in USD</td>
<td>{{ $invoices_usd->whereYear('paid_at', \Carbon\Carbon::parse($date)->year)->whereMonth('paid_at', \Carbon\Carbon::parse($date)->month)->sum('total') * \App\ConversionRate::dollarToEGP() }}</td>
#endif
</tr>
<tr>
#if(count($orders->get()))
<td colspan="100%">Orders</td>
<td>{{ $orders->whereYear('paid_at', \Carbon\Carbon::parse($date)->year)->whereMonth('paid_at', \Carbon\Carbon::parse($date)->month)->sum('total') }}</td>
#endif
</tr>
</tbody>
</table>
</div>
</div>
#endforeach
#else
<div class="card-box">
<h3>No Data</h3>
</div>
#endif
</div>
Here when I loop over the $dates variable, for some reason, the $invoices_egp variable changes based on the date, even though it has got nothing to do with it, if I tried to dump $invoices_egp (which has two records with the same date 2019-01) on each loop, I am expecting to get the two records twice regardless of the date, instead I get the two records on the first loop ($date = 2019-03), and on the second loop ($date = 2019-01) I get an empty collection.
I have tried different stuff, I replaced the dates variable with a hard coded array and removed the other dates queries, nothing changes in the blade file.
What's even weirder is that if I changed the place of $invoices_egp with $invoices_usd, I get $invoices_egp rendered correctly, and the bug instead happens to the $invoices_usd variable, so whatever the first variable is, it gets messed up.
Small Update
I don;t know what's wrong yet, but as soon as I comment out this line
<td>{{ $invoices_egp->whereYear('paid_at', \Carbon\Carbon::parse($date)->year)->whereMonth('paid_at', \Carbon\Carbon::parse($date)->month)->sum('total') }} EGP</td>
I get the variable rendering twice correctly per each instance of the loop, which is what should happen, and this line I am commenting should not have any impact over whether the collection should be retrieved successfully or not, I hope I am making sense.
If I dump the variable over each loop, this is what I get in the first loop
Collection {#522 ▼
#items: array:2 [▼
0 => Invoice {#526 ▶}
1 => Invoice {#519 ▶}
]
}
And this is what I get in the second loop (with the aforementioned line uncommented)
Collection {#516 ▼
#items: []
}
Same variable, different results over a loop.
So apparently since I was passing a query builder instance to the view, it was actually getting changed by the foreach loop, which is something I'd never thought would happen, anyway the fix was easy at that point, just had to change the code a little, starting from here:
public function index()
{
$invoices_egp = auth()->user()->invoices()->where(['paid' => 1, 'currency' => 'EGP'])->latest()->get();
$invoices_usd = auth()->user()->invoices()->where(['paid' => 1, 'currency' => 'USD'])->latest()->get();
$orders = \App\Order::where('vendor_id', auth()->user()->id)->where('paid', 1)->latest()->get();
$egp_invoices_dates = $invoices_egp->map(function($invoice) { return Carbon::parse($invoice->paid_at)->format('Y-m'); })->unique();
$usd_invoices_dates = $invoices_usd->map(function($invoice) { return Carbon::parse($invoice->paid_at)->format('Y-m'); })->unique();
$orders_dates = $orders->map(function($order) { return Carbon::parse($order->paid_at)->format('Y-m'); })->unique();
$dates = $orders_dates->merge($usd_invoices_dates)->merge($egp_invoices_dates)->unique();
return view('dashboard.vendor.reports.index', compact('invoices_egp', 'invoices_usd', 'orders', 'dates'));
}
And in the view I just had to change the filtering queries to be like this for all 3 queries:
<td>{{ $invoices_egp->filter(function($invoice) use ($date) { return $invoice->created_at->year == \Carbon\Carbon::parse($date)->year; })->filter(function($invoice) use ($date) { return $invoice->created_at->month == \Carbon\Carbon::parse($date)->month; })->sum('total') }} EGP</td>

Select values from a table where Ids are in json format in another table in laravel

I have a table named journal_details and it has a column named transaction_by_to. I am saving account_head_id values as json_encode format in transaction_by_to in table journal_details. Now I want to run a select query to get account head names from account_heads where transaction_by_to ids in JSON format will find the id from account_heads. In the controller, I tried something like bellow, but it's getting only one. But I want to show all from account_heads for all JSON formatted ids.
public function ledgerSubmit(Request $request)
{
$acId = $request->acount_head;
$startDate = Carbon::parse($request->start_date)->format('Y-m-d');
$endDate = Carbon::parse($request->end_date)->format('Y-m-d');
$reportType = $request->report_type;
$nameOfAccount = AccountHead::find($acId);
$ledgers = DB::table('journal_details')
->join('journals', 'journal_details.journal_id', '=', 'journals.id')
->join('account_heads', 'journal_details.account_head_id', '=', 'account_heads.id')
->where('journal_details.account_head_id', $acId)
->select('journals.number as journalNo', 'journals.journal_date as journalDate', 'journal_details.*', 'account_heads.name as nameOfAccount')
->get();
if (count($ledgers)) {
$transactionByToId = $ledgers[0]->transaction_by_to;
foreach (json_decode($transactionByToId) as $tId) {
$transactionByTo = AccountHead::where('id', $tId)->get();
}
}
return view('report.ledger.searched-result', compact('reportType', 'startDate', 'endDate', 'ledgers', 'transactionByTo', 'nameOfAccount'));
}
And in blade view-
#foreach($ledgers as $ledger)
<tr>
<td>{{ $loop->index + 1 }}</td>
<td>{{ $ledger->journalNo }}</td>
<td>{{ date('jS F, Y', strtotime($ledger->journalDate)) }}</td>
<td>{{ $ledger->nameOfAccount }}</td>
<td>
{{ $transactionByTo[0]->name }}
</td>
<td>
{{ number_format($ledger->debit, 2,".",",") }}
</td>
<td>
{{ number_format($ledger->credit, 2,".",",") }}
</td>
</tr>
#endforeach
["16","17","7","11"] is transaction_by_to column values in json format in journal_details and these ids are id for account_heads table.
There are several errors in your code, like in following code:
foreach (json_decode($transactionByToId) as $tId) {
$transactionByTo = AccountHead::where('id', $tId)->get();
}
it will always keep single value, the last value. So it will seem that there is only one record.
But why don't you do following to get all records at a time:
$accountHeadIds = json_decode($transactionByToId, true);
$accountHeads = AccountHead::whereIn('id', $accountHeadIds)->get();
Secondly, I don't see you are processing Account Head variable (as per my code example, $accountHeads) in the view file that is not part of $leders variable. If you want to have that under $ledgers variable then you should store under it.
Note: I haven't tested the code above, but the concept is similar.

Laravel show different date from my database

I have a problem in my project. When I store value in my database it works perfectly fine. But when I want to show the value it gives me an undefined date that is not stored in my database.
Here In my database the created_at field value is 2017-02-18 16:23:37. But When I want to show this in my view page it gives me this
It gives me the value of 2017-02-02 09:19:40. I don't understand whats wrong.
I am only showing the created_at field. Please help me
My controller is
public function showApplication() {
$dataList = ApplicationModelOL::leftJoin('certificate', 'application.application_certificate_id', 'certificate.certificate_track_id')
->where('application_users_id', Auth::User()->users_track_id)
->get();
return view('frontend.pages.application', compact('dataList'));
}
My view is
#foreach($dataList as $data)
<tr>
<td>{{ $data->certificate_name_en }}</td>
#if($data->application_delivery_mode == 195126)
<td>Self</td>
#else
<td>Via Post</td>
#endif
<td class="hidden-phone">{{ $data->created_at }}</td>
<td class="hidden-phone">
<span class="label label label-warning">Pending</span>
</td>
<td class="hidden-phone">
<span class="label label-primary"><i class="fa fa-edit"></i></span>
<span class="label label-danger"><i class="fa fa-trash"></i></span>
</td>
</tr>
#endforeach
This problem happens when your MySQL timezone is different from php timezone which is set in your framework.
to sync your timezone you can use following codes:
PHP:
date_default_timezone_set('Asia/Tehran');
MySQL:
$timeZone = (new DateTime('now', new DateTimeZone('Asia/Tehran')))->format('P');
$pdo->exec("SET time_zone='$timeZone';");
With Mysql attributes, you can get different values whether id or created_at(Laravel) if you use join on tables. Say you join three tables the output will return the last column of the three "created_at". Therefore you could just check to make sure your joins are correct.
You can change your timezone in Laravel in your config/app.php.
The param below can be changed to whatever your preference is in line with the supported timezones...
'timezone' => 'Europe/Dublin',

Categories