Multiple query inside foreach loop in Laravel - laravel

I've been scratching my head over this since last night. I have this function on my controller:
public function generate_documents($id)
{
$contract = Contract::find($id);
$booking_ids = $contract->booking_id;
$booking_ids = json_decode($booking_ids);
$bookings = Booking::find($booking_ids);
}
$booking_ids returns a json of ids that are stored in the database. I then find the booking records based on the IDs.
foreach($bookings as $booking) {
$asset = Omg_asset::where('id', $booking->omg_asset)->first();
}
Here's the part where I am expecting 3 results but only the last one gets returned on my view. I tried this method:
$asset = '';
foreach($bookings as $booking) {
$asset .= Omg_asset::where('id', $booking->omg_asset)->first();
}
But whenever I try to retrieve the values on my view, it's returning a json containing all the records I need and I can't access it via index.
Attaching a screenshot for better context:
Here's my code on my view by the way:
#foreach($bookings as $booking)
<tr>
<td>{{ $asset }}</td>
</tr>
#endforeach
Here's the error thrown whenever I try to do {{ $asset['asset_name'] }} on view:
"Illegal string offset 'asset_name'"
I haven't used Laravel in a long time so I would really appreciate your help. If there's also a better way to do this, I'm open for suggestions.
Thanks in advance!

Related

Call to a member function count() - I have faced the issue for View page showing error

Please check the below code for view and controller.
Controller:
$staffreply = StaffReply::where('ticket_id', '=', $ticketID)->orderBy('id', 'asc')->get();
if ($staffreply->count()) {
//Get the data values
} else {
$staffreply = "";
$supportstaff = "";
$supportteam = "";
}
return view('pages/support/service-view',compact('data','staffreply','supportstaff','supportteam'));
View Page:
#if($staffreply->count())
#foreach($staffreply as $supportDesk)
<span>Posted on {{$supportDesk->created_date;}}</span>
#endforeach
#endif
Error:
Call to a member function count() on int (View: --\htdocs\laravel\project\resources\views\pages\support\service-view.blade.php)
How to solve the issue.
Even though it is not clear what $staffreply is. You can't use count() on non-Arrayables.
First make sure that $staffreply is in fact a collection in the controller. If not, the fallback in the else should probably equal an empty collection and not a 0. If so, in the view you wouldn't need to check if $staffreply->count().
Thanks for the support, after I have edited the view page code issue solved.
Edited Code
#if($staffreply != "")
#foreach($staffreply as $supportDesk)
<span>Posted on {{$supportDesk->created_date;}}</span>
#endforeach
#endif

Reducing amount of queries, page loading slow [duplicate]

This question already has answers here:
Laravel sorting last record
(5 answers)
Closed 2 years ago.
I'm trying to minimize the amount of queries I'm using by "eager loading" a threads' replies pagination. But I'm a little unsure how to do it. Below is the code:
$unpinnedThreads = Thread::all()->sortByDesc(function($thread) {
$replies = $thread->replies->sortByDesc('created_at');
$lastTouchedPost = Carbon::minValue();
if (!empty($replies->toArray())) {
$lastTouchedPost = $lastTouchedPost->max($replies->first()->created_at);
}
return $lastTouchedPost->max($thread->created_at);
});
View:
#foreach($thread->replies->paginate(15)->setPath($thread->path())->getUrlRange(ceil($thread->replies->count()
/ 15 - 2), ceil($thread->replies->count() / 15)) as $key => $pagination)
#if($key > 1)
{{ $key }}
#endif
#endforeach
So far I have alot of queries in the debug bar that looks like this:
select * from `replies` where `replies`.`thread_id` = ? and `replies`.`thread_id` is not null
I was wondering how I could reduce the number of queries.
When I code: Thread::with('replies')->sortByDesc->, it throws calls to undefined method. However when I code ->with('replies'), it throws an error that says:
Method Illuminate\Database\Eloquent\Collection::with does not exist.
Can anyone please help me?
Thank you.
Edit::
I've deduced the issue is in my method:
$unpinnedThreads = Thread::all()->sortByDesc(function($thread) {
$replies = $thread->replies->sortByDesc('created_at');
$lastTouchedPost = Carbon::minValue();
if (!empty($replies->toArray())) {
$lastTouchedPost = $lastTouchedPost->max($replies->first()->created_at);
}
return $lastTouchedPost->max($thread->created_at);
});
Does anyone know how I can optimize the method?
Answer found here: Laravel sorting last record
"One solution I would suggest is to have the replied touch the topics. https://laravel.com/docs/5.3/eloquent-relationships#touching-parent-timestamps
This way you can always order by the Topic's updated_at because whenever a reply is created/edited it will update the Topic as well.
To achieve this you would just need to add:
protected $touches = ['topic'];
The above is assuming that the method name for the topics relationship in the replies model is topic().
Hope this helps!"
That is really strange. It appears that you are calling with() in the model Thread::with('replies'), but the error is saying that you are calling it on a collection. The collection object does not have the with() method.
The bellow code should work:
$collection = Thread::with(['replies'])->get()->sortByDesc(function($thread)
{
if (count($thread->replies))
{
return $thread->replies->sortBy('created_at')->last()->created_at;
}
else
{
return $thread->created_at;
}
});
If you are not using the defaults, created_at must be configured:
protected $casts = [
'created_at' => 'date',
]
Don't forget to create the relationship inside your Thread model:
public function replies()
{
return $this->hasMany(Reply::class, 'thread_id', 'id');
}

Laravel running totals or balance with paginate

I am really new to laravel and quite new to codding. I am surprise that running totals or balances don't receive a lot of attention.
The problem is:
I have the current balance of an account recorded in the database.
I have a page called account/$id, where I get all the transactions of the account with that id.
My last column is the balance of the account id after that transaction. A reverse running total, I think it is called. Example: balance of transaction 3 = balance of transaction 2 - ammount of transaction 2.
Until here everything works.
However, when I enter paginate; only the first page give me the correct balance. In the second the balance restarts from the begining.
Code that works:
Controller
$transactions=\App\Transaction::orderByDesc('transaction_date')->orderByDesc('created_at')->where('account_id',$id)->get();
$previousTransaction=0;
$previousBalance=$account->account_current_balance;
foreach ($transactions as $key => $transaction) {
$balances[]=$previousBalance-$previousTransaction;
$previousBalance=array_values($balances)[++$key-1];
$previousTransaction = $transaction->transaction_ammount;
}
View
#foreach($transactions as $key => $transaction)
<td class="align">{{array_values($balances)[++$key-1]}}</td>
#endforeach
Code that doesn't give me the correct balance:
Controller
$transactions=\App\Transaction::orderByDesc('transaction_date')->orderByDesc('created_at')->where('account_id',$id)->paginate(20);
$previousTransaction=0;
$previousBalance=$account->account_current_balance;
foreach ($transactions as $key => $transaction) {
$balances[]=$previousBalance-$previousTransaction;
$previousBalance=array_values($balances)[++$key-1];
$previousTransaction = $transaction->transaction_ammount;
}
View
#foreach($transactions as $key => $transaction)
<td class="align">{{array_values($balances)[++$key-1]}}</td>
#endforeach
<div class="content-header noevents">
{{ $transactions->links() }}
</div>
I have tryed as well different appends in links(), but it seems that I don't know how to use it or doesn't work.
Really big thanks in advance to anyone that can help me.
problem :
every time you navigate through pagination links, you actually send a get request to the same URL, plus ?page=N (N: link number) E.g.
https://example.com/account/36?page=2.
and each time controller should execute, and at the beginning, it set
$previousTransaction=0;
$previousBalance=$account->account_current_balance;
solution:
I don't have your complete code, but your controller should be something like this:
public function ControllerFunction(Request $request){
$transactions=\App\Transaction::orderByDesc('transaction_date')->orderByDesc('created_at')->where('account_id',$id)->paginate(20);
if(!$request->has(['pre_trans', 'pre_balance']){
$previousTransaction=0;
$previousBalance=$account->account_current_balance;
}else{
$previousTransaction = $request['pre_trans'];
$previousBalance = $request['pre_balance'];
}
foreach($transactions as $key => $transaction) {
$balances[]=$previousBalance-$previousTransaction;
$previousBalance=array_values($balances)[++$key-1];
$previousTransaction = $transaction->transaction_ammount;
}
if(!$request->has(['pre_trans', 'pre_balance']){
$request->request->add(['pre_trans' => $previousTransaction]);
$request->request->add(['pre_balance' => $previousBalance]);
}else{
$request['pre_trans'] = $previousTransaction;
$request['pre_balance'] = $previousBalance;
}
}

Get an object in codeigniter

I don't know if it's possible but, I've two table with a relation one-to-many (players->statistics).
I get all the stats with this method :
return $this->db->get('statistics')->result_array();
Which means I also get the player_id in there, but I can get it as a string and not as an object.
What I wanted to do is this (Twig) :
{{stat.player_id.name}}
But that doesn't work as it's not an object.
Is it possible to do that in Codeigniter and how ?
You mean something like this :
$this->db->select('*');
$this->db->from('statistics');
$this->db->join('joueurs', 'joueurs.id = statistics.player_id');
return $query = $this->db->get()->result_array();
Yes you can do it in codeIgniter
instead of result_array() you need to use result()
return $this->db->get('statistics')->result();
With the help of joins in codeIgniter you can achieve your desire result
It's not working for me. I'm probably missing something.
Here's my function in Statistics_model.php :
function get_all_statistics()
{
$this->db->select('*');
$this->db->from('statistics');
$this->db->join('joueurs', 'joueurs.id = statistics.player_id');
return $query = $this->db->get()->result();
}
Index action in the controller :
function index()
{
$data['statistics'] = $this->Statistic_model->get_all_statistics();
$this->load->library('twig');
$this->twig->display('statistics/index', $data);
}
And finally the view :
{% for stat in statistics %}
<tr>
<td>{{stat.stat_id}}</td>
<td>{{stat.leg_id}}</td>
<td>{{stat.player_id.name}}</td>
<td>{{stat.darts}}</td>
<td>{{stat.finish}}</td>
<td>{{stat.reste}}</td>
<td>{{stat.max}}</td>
</tr>
{% endfor %}
Everything works fine but, I cannot get the player name

CodeIgniter Table Class: Add a Link From a Generated Cell

I'm using the table class that auto-generates a table for me from an array of data pulled from my database.
Model:
function get_reports_by_user_id($userid)
{
return $this->db->get_where('ss2_report',array('userid' => $userid))->result_array();
}
Controller:
function index()
{
echo $this->table->generate($this->mymodel->get_reports_by_user_id('1234'));
}
The controller will eventually be moved to a view when I have it working. This generates the table just fine, but I'd like to add a link to a field. For example, the id column that would allow me to link to a page of data for just that report's id. I know I can just output the table the old fashioned way by hand. I can then add whatever links I want, but I'd love to be able to use the auto-generation as much as possible. There's got to be a way to do something as common as linking a table cell. Does anyone have any ideas?
EDIT:
User Java PHP has it mostly right below. Here's the code that makes it work:
function get_reports_by_user_id($userid)
{
$rows = $this->db->get_where('ss2_report',array('userid' => $userid))->result_array();
foreach ($rows as $count => $row)
{
$rows[$count]['id'] = anchor('report/'.$row['id'],$row['id']);
}
return $rows;
}
I just needed to replace the value in the original array with the anchor text version.
The only way is, in the function get_reports_by_user_id() , you would loop through all the results and add the <a href> tag to the ids. Something like this:
function get_reports_by_user_id($userid)
{
$rows=$this->db->get_where('ss2_report',array('userid' => $userid))->result_array();
foreach ($rows as $row)
{
$row->id=anchor('site.com/some_controller/some_function/'.$row->id,$row->id);
}
return $rows;
}
I don't use CodeIgniter's database library so I'm not sure of what format it returns $rows in, but the code above should give you the general idea of what you need to do.
One idea might be to do something like..
foreach ($row in $this->mymodel->get_reports_by_user_id('1234'))
{
$row->id = anchor(site_url(array('report', 'user', $row->id)), $row->id);
$this->table->add_row($row);
}
$this->table->generate();

Resources