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

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!

Related

Format number to K/M/B within blade template

I am using laravel 5.7.19.
Within my TableController.php controller I query data from my db and hand it over to the view:
public function index()
{
$c = DB::table('tick_data')
->select('*')
->join('basis', 'basis.Id', '=', 'tick_data.b_id')
->whereRaw('tick_data.id IN( SELECT MAX(tick_data.id) FROM tick_data GROUP BY tick_data.exchange_timestamp)')
->get();
return view('datatable')->with('coins', $c);
}
Within my table.blade.php file I am putting the data out:
#foreach ($coins as $key=>$c)
<tr>
<td>{{ ++$key }}</td>
<td>{{ $c->pair }}</td>
<td>{{ number_format($c->last_price, 8) }}</td>
<td>{{ number_format($c->price_change_percentage, 8) }}</td>
<td>{{ number_format($c->price_change, 8) }}</td>
<td>{{ number_format($c->high_price, 8) }}</td>
<td>{{ number_format($c->low_price, 8) }}</td>
<td>{{ $c->base_volume }}</td>
<td>{{ $c->name }}</td>
</tr>
#endforeach
As you can see I am mainly using the number_format() function for formatting my values.
However, base_volume comes in the form of 467703.0000000000 or 10831.13202978000 and I would like to change it to the shortform with K,M,B.
Is there any function in blade that can do this? What is a good way to preformat the numbers?
Appreciate your replies!
I don't know any blade functions that can do this. However, you can use the PHP Humanizer package for this. For example, from their documentation:
use Coduo\PHPHumanizer\NumberHumanizer;
NumberHumanizer::metricSuffix(-1); // "-1"
NumberHumanizer::metricSuffix(0); // "0"
NumberHumanizer::metricSuffix(1); // "1"
NumberHumanizer::metricSuffix(101); // "101"
NumberHumanizer::metricSuffix(1000); // "1k"
NumberHumanizer::metricSuffix(1240); // "1.2k"
NumberHumanizer::metricSuffix(1240000); // "1.24M"
NumberHumanizer::metricSuffix(3500000); // "3.5M"
The good thing about the package is, it also supports multiple locales.
Edit: There are also other alternative solutions as discussed here. This could be a better option for you if you just need to shorten numbers.

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.

Validation for Laravel object variable that is empty or does not exist

I am trying to figure out the best or simplest way to handle a Laravel object variable that is empty or does not exist.
For now I have tried to do this; I have come up with 2 solutions but both of them I feel are not the simplest or cleanest way.
First way is in controller after getting Laravel object, I do a foreach loop and in there I do checking if there is empty or not exist variable, if yes then replace it with '-'.
So in my controller it will be:
$dataarticle = Article::with('categories')
->get();
$i = 0;
foreach($dataarticle as $data){
$datas[$i] = array(
'id' => !empty($data->id) ? $data->id : '-',
'name' => !empty($data->name) ? $data->name : '-',
'category' => !empty($data->categories->name) ? $data->categories->name : '-',
'created_at' => !empty($data->created_at) ? $data->created_at : '-',
);
$i++;
}
and in my view I just do another foreach loop in my table.... it looks good but it also means I need to do 2 times foreach.
The other approach is do a variable check in view so I just need to do foreach loop once... but it will make my view code to be messy.. like this
#foreach($datas2 as $data)
<tr>
<td class="bg-aqua disabled color-palette"></td>
<td hidden>{{ $data->id }}</td>
#if(!empty($data->name))
#if($data->id > 1)
<td>{{ $data->name }}</td>
#else
<td>{{ $data->name }}</td>
#endif
#else
<td>-</td>
#endif
#if($data->hasartikel->count() > 0)
<td><a class="btn btn-default" disabled>{{ $data->jumlah }}</a></td>
#else
<td><a href="#" class="btn btn-default" disabled>{{ $data->hasartikel->count() }}</a> </td>
#endif
</tr>
#endforeach
so maybe there is a function or method or command to do it in much more simpler way?
It will be very tiring if you have a lot of variables in your table and keep to do pretty much the same thing for each variable.
Just add getFieldAttribute in your model for each field, so it can be used anywhere by just one time config
class Article extends Model
{
public function getNameAttribute($value)
{
return !empty($value) ? $value : '-';
}
}
So , in view can simply call the variable as below. No need to reformat
<td>{{ $data->name }}</td>
Check details here
Make all you need field required!!!!!!!!! ) and be happy

Laravel Eloquent splitting query into array

Bit of a bad title, not quite sure how to research/describe what I'm trying to do.
I have a table called specifications with the fields
id, device_id, name, detail
Two rows for two different devices would for example be
1, 1, weight, 300kg
2, 2, weight, 250kg
Now the way I need to display it is in a single table compare both devices, essentially like this:
#foreach($specifications as $specification)
<tr>
<td>{{ $specification->name }}</td>
<td>{{ $specification->detailOne }}</td>
<td>{{ $specification->detailTwo }}</td>
</tr>
#endforeach
I'm having issues getting the right query or split the query in order to be able to go through the array like above. Anyone mind putting me on the right mindset? Do I query both specs and somehow resort it into an array I can use as above, or is there something else I should be looking at?
This should work for you
#foreach($specifications->groupBy('name') as $name => $specificationGrouped)
<tr>
<td>{{ $name }}</td>
#foreach($specificationGrouped as $specification)
<td>{{ $specification['detail'] }} ({{ $specification['device_id'] }})</td>
#endforeach
</tr>
#endforeach

What is the right way to iterate over nested array in Twig

I have this function on a repository:
public function getSolicitudes($usuario_id)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('su.id, su.fecha_creacion, tt.nombre AS tipo_tramite, tr.nombre AS tipo_registro, es.nombre AS estado_solicitud')
->from("ComunBundle:SolicitudUsuario", "su")
->where('su.usuario = :usuario_id')
->join('su.tipo_tramite', 'tt', \Doctrine\ORM\Query\Expr\Join::INNER_JOIN)
->join('su.tipo_registro', 'tr', \Doctrine\ORM\Query\Expr\Join::INNER_JOIN)
->join('su.estado_solicitud', 'es', \Doctrine\ORM\Query\Expr\Join::INNER_JOIN)
->orderBy('su.fecha_creacion', 'DESC')
->setParameter('usuario_id', $usuario_id);
return $qb->getQuery()->getResult();
}
In Twig template I have this:
{{ entities|ladybug_dump }}
And the output is something like image show:
I'm trying to iterate over the result in Twig template as follow:
{% for solicitud in entities %}
<tr>
<td></td>
<td>{{ solicitud.tramite }}</td>
<td>{{ solicitud.id }}</td>
<td>{{ solicitud.solicitud }}</td>
<td>{{ solicitud.estado }}</td>
<td>{{ solicitud.fecha }}</td>
<td></td>
</tr>
{% endfor %}
But I got this error:
Key "tramite" for array with keys "id, fecha_creacion, tipo_tramite,
tipo_registro, estado_solicitud" does not exist in
/var/www/html/src/RPNIBundle/Resources/views/Listado/index.html.twig
at line 25
What I'm missing here?
It's obvious, you're using the wrong key, as the exception suggests:
Key "tramite" for array with keys "id, fecha_creacion, tipo_tramite, tipo_registro, estado_solicitud" does not exist in /var/www/html/src/RPNIBundle/Resources/views/Listado/index.html.twig at line 25
Your object has a tipo_tramite key, not tramite. You should change the output statements.

Categories