How to get all records in laravel Models - php

I'm not using eloquent, my models are like this.
class drivers extends Model
{
}
I want to display records of all drivers ( one record in each row )
My driver table has field (driver_id,name,tyre_id)
My tyre table has field (id, title)
My bank table has field (id, driver_id, bank)
I want my record to be like this...
Driver Id, Name, Bank Details, Tyre Title
100000111, Ayer, Available, GO
.. so on
For bank details if driver_id has a record in bank table, it should display available otherwise N/A.
$drivers= Drivers::get();
$myarray = ();
foreach ($drivers as $d){
$bank = Bank::where('driver_id',$d->driver_id)->first();
$tyre = Tyre::where('id',$d->tyre_id)->first();
$myarray[] = $d->driver_id;
$myarray[] = $d->name;
$myarray[] = isset($bank) ? "available" ; '';
$myarray[] = $tyre->title;
}
This is what i have tried, I'm to new to laravel, how can i achieve this in laravel or using query like DB Table?

Laravel offers two very useful tools for performing database operations eloquent and query builder. It is advisable to work as much as possible with eloquent and their relationships as it facilitates much of the common operations that we normally need to perform.
Now, if you want to make more complex queries you can use query builder, also, an example of your case using query builder would be something like this:
In your controller you make the query and pass the data to view:
$data = DB::table('driver')
->leftJoin('bank', 'bank.driver_id','=', 'driver.driver_id')
->join('tyre', 'tyre.id','=', 'bank.tyre_id')
->select('driver.driver_id as id',
'driver.name',
'bank.id as bank_id',
'tyre.title')
->groupBy('driver.driver_id')
->get()
And in your view you can use a foreach loop to display the data (and you can use a conditional to display the bank field):
<table>
<thead>
<tr>
<th>Driver ID</th>
<th>Name</th>
<th>Bank Detail</th>
<th>Tyre Title</th>
</tr>
</thead>
<tbody>
#foreach($data as $item)
<tr>
<td>{{ $item->id }}</td>
<td>{{ $item->name }}</td>
<td>{{ isset($item->bank_id) ? "availible":"N/A" }}</td>
<td>{{ $item->title }}</td>
</tr>
#endforeach
</tbody>
</table>
likewise I recommend you read the documentation of eloquent and try to use it.
https://laravel.com/docs/5.5/queries
https://laravel.com/docs/5.5/eloquent

The Good way to Solve this is laravel relations
here the link
laravel documentation
Select your driver table as base table and use relations to get the other table fields;
array_push() function to push values to array

Another way is using DB Facade with joins: Like this:
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();

Related

Dynamic column/attribute. Stuck. Need inspiration

i’m looking for a solution to a problem that I’m having for a while now. Maybe you can inspire me to do this better. I’m trying not to make a basic mistake in the planning process therefore I’m asking you for advice.
I’m having a Contact::model which has few fixed attributes like id etc. Additionally I would like to have different attributes created dynamically for the whole Contact::model. Some user will be given the functionality to add attributes like name, email, address to the whole model. I’ve dropped the idea of programmatically updating the table itself by creating/dropping columns (this would introduce different problems). As for now i've created two additional tables. One with the additional column names [Columns::model] and a pivot table to assign the value to a Contact::model and Column::model.
To list all contacts i’m preparing the ContactColumn table as array where the first key is the contact_id and the second is the column_id, therefore i get the value. This introduces the n+1 issue. This would not be that bad, but with this approach it will be extremely hard (or resource consuming) to order the contacts by dynamic column values, filtering, searching etc.
Can you somehow guide me to a better solution. How can i merge the contact collection with the values for given columns so it looks like it was a fixed table?
<table>
<thead>
<tr>
<th>Fixed columns [i.e. ID]</th>
#foreach ($columns as $column)
<th>{{ $column->name }}</th>
#endforeach
</tr>
</thead>
<tbody>
#foreach ($contacts as $contact)
<tr>
<td>{{ $contact->id }}</td>
#foreach ($columns as $column)
<td>
#if (array_key_exists($column->id, $values[$contact->id]))
{{ $values[$contact->id][$column->id] }}
#endif
</td>
#endforeach
</tr>
#endforeach
</tbody>
</table>
And the $value array.
foreach (ColumnContact::all() as $pivot) {
$values[$pivot->contact_id][$pivot->column_id] = $pivot->value;
}
return $values;
Edit: I've solved it like this
$this->contacts = Contact::when($this->dynamicColumnName, function($query) {
$query->join('column_contact', function ($join) {
$join->on('id', '=', 'column_contact.contact_id')
->where('column_contact.column_id', '=', $this->dynamicColumnName->id);
})
->orderBy('value', $this->orderingDirection);
})
(...)
->paginate(self::PER_PAGE);
Apart from the fixed fields, add an extra JSON field in your schema called 'custom_fields'. Have a look into => https://github.com/stancl/virtualcolumn
Separate table for custom fields is not a good idea because then you have to handle model events separately and so on.

Laravel orderby with relationship

i'm trying to sort the student list by each level with using relationship method with OrderBy function but unfortunately i can't make it work any idea whats missing on my code?
Note:
every-time i remove the orderby my code will work but students level are not arrange accordingly
Controller:
$students=Student::with('level')->where(['status' => 'ENROLLED'])->get()->orderBy('level_name','asc');
View
<table>
<tr>
<th>Name</th>
<th>Level</th>
</tr>
#foreach($students as $std)
<tr>
<td>
{{$std->student_name}}
</td>
<td>
#foreach($std->level as $lv)
{{$lv->level_name}}
#endforeach
</td>
</tr>
#endforeach
</table>
You can't order by a relationship because under the hood laravel makes two seperate queries under the hood.
You can instead use a join, something like this (beware I guessed your table names, so you may have to update them).
$users = Student::join('levels', 'students.level_id', '=', 'levels.id')
->orderBy('levels. level_name', 'asc')->select('students.*')->paginate(10);
Try this:
Controller:
$students = Student::with(['level' => function (Builder $query) {
$query->orderBy('level_name', 'asc');
}])->where(['status' => 'ENROLLED'])->get();
In addition you can add orderBy() to relation method.
Student Model:
public function level()
{
return $this->relationMethod(Level::class)->orderBy('level_name', 'asc');
}
Try this
$students=Student::with('level')->where(['status' => 'ENROLLED'])->orderBy('level_name','asc')->get();

Laravel - Math computations in blades

Is it possible to add two integers from the database inside a blade?
To give a scenario, I have a controller that compacts a collection of orders table.
$solditems = DB::table('orders')
->where('status', 'served')
->orderBy('id')
->get();
return view('salesreports.sellingitems.index', compact('solditems'));
And I used those like this in my blade.
<table class="table table-hover">
<tr>
<th>ID</th>
<th>Item</th>
<th>Sales</th>
</tr>
<thead>
</thead>
<tbody>
#forelse($solditems as $solditem)
<tr>
<td>{{$solditem->id}}</td>
<td>{{$solditem->item}}</td>
<td>{{$solditem->subtotal}}</td>
</tr>
#empty
#endforelse
</tbody>
</table>
Now, what I want to do is to combine an item that has same item names or $solditem->item while adding up there subtotals.
For example;
ID #1 Apple = 50
ID #2 Apple = 80
Will become this;
ID #1 Apple = 130
I tried using groupBy on query builder so an item with same name will only show once, but I'm having problems designing an algorithm adding up the subtotal.
Try this one,
This gives you sum of cost with same item name for all items.
$solditems = DB::table('orders')
->where('status', 'served')
->select('orders.*',DB::raw('SUM() as total'))
->groupBy('orders.item')
->orderBy('id')
->get();
You could take advantage of Laravel's collection methods. You can use the GroupBy method to create grouped subarrays by product name and foreach of those group using the Sum method return the sum of the total column.

Laravel Eloquent: Reduce number of queries

Let's say I have 250 users in users table and each user has one or many books, and each book has one or many chapters. Now I would like to print the user names, with their book names.
Controller:
$users = User::all();
in blade:
#foreach($users as $user)
<tr>
<td>{{ $user->id }}</td>
<td>{{ $user->name }}</td>
<td>
#foreach($user->books as $book)
{{ $book->name }},
#endforeach
</td>
</tr>
#endforeach
# of queries 252
Now to overcome the n+1 problem, the query should be
$users = User::with('books')->get();
Now the # of queries are only 2.
I want to print the book names with number of chapters like this->
BookName(# of chapters). So in my blade
#foreach($users as $user)
<tr>
<td>{{ $user->id }}</td>
<td>{{ $user->name }}</td>
<td>
#foreach($user->books as $book)
{{ $book->name }} ({{ $book->chapters->count() }}),
#endforeach
</td>
</tr>
#endforeach
so for 750 books with 1500 chapters the # of queries are about 752 and it increases if chapter number increases.
Is there any better Eloquent way to reduce it or should I go for raw SQL queries?
You don't need to load all chapters data and then manually count each collection. Use withCount() instead:
$users = User::with('books')->withCount('chapters')->get();
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
From the Eloquent Documentation:
Nested Eager Loading
To eager load nested relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts in one Eloquent statement:
$books = App\Book::with('author.contacts')->get();
In your case, you can retrieve the nested relationships you need with the following:
User::with('books.chapters')->get();

Trying to get property of non-object - Laravel 5

I'm trying to echo out the name of the user in my article and I'm getting the
ErrorException: Trying to get property of non-object
My code:
Models
1. News
class News extends Model
{
public function postedBy()
{
return $this->belongsTo('App\User');
}
protected $table = 'news';
protected $fillable = ['newsContent', 'newsTitle', 'postedBy'];
}
2. User
class User extends Model implements AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
protected $table = 'users';
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['password', 'remember_token'];
}
Schema
table users
table news
Controller
public function showArticle($slug)
{
$article = News::where('slug', $slug)->firstOrFail();
return view('article', compact('article'));
}
Blade
{{ $article->postedBy->name }}
When I try to remove the name in the blade {{ $article->postedBy }} it outputs the id, but when I try to add the ->name there it says Trying to get property of non-object but I have a field namein my table and aUser` model. Am I missing something?
Is your query returning array or object? If you dump it out, you might find that it's an array and all you need is an array access ([]) instead of an object access (->).
I got it working by using Jimmy Zoto's answer and adding a second parameter to my belongsTo. Here it is:
First, as suggested by Jimmy Zoto, my code in blade
from
$article->poster->name
to
$article->poster['name']
Next is to add a second parameter in my belongsTo,
from
return $this->belongsTo('App\User');
to
return $this->belongsTo('App\User', 'user_id');
in which user_id is my foreign key in the news table.
If you working with or loops (for, foreach, etc.) or relationships (one to many, many to many, etc.), this may mean that one of the queries is returning a null variable or a null relationship member.
For example: In a table, you may want to list users with their roles.
<table>
<tr>
<th>Name</th>
<th>Role</th>
</tr>
#foreach ($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->role->name }}</td>
</tr>
#endforeach
</table>
In the above case, you may receive this error if there is even one User who does not have a Role. You should replace {{ $user->role->name }} with {{ !empty($user->role) ? $user->role->name:'' }}, like this:
<table>
<tr>
<th>Name</th>
<th>Role</th>
</tr>
#foreach ($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ !empty($user->role) ? $user->role->name:'' }}</td>
</tr>
#endforeach
</table>
Edit:
You can use Laravel's the optional method to avoid errors (more information). For example:
<table>
<tr>
<th>Name</th>
<th>Role</th>
</tr>
#foreach ($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ optional($user->role)->name }}</td>
</tr>
#endforeach
</table>
If you are using PHP 8, you can use the null safe operator:
<table>
<tr>
<th>Name</th>
<th>Role</th>
</tr>
#foreach ($users as $user)
<tr>
<td>{{ $user?->name }}</td>
<td>{{ $user?->role?->name }}</td>
</tr>
#endforeach
</table>
I implemented a hasOne relation in my parent class, defined both the foreign and local key, it returned an object but the columns of the child must be accessed as an array.
i.e. $parent->child['column']
Kind of confusing.
REASON WHY THIS HAPPENS (EXPLANATION)
suppose we have 2 tables users and subscription.
1 user has 1 subscription
IN USER MODEL, we have
public function subscription()
{
return $this->hasOne('App\Subscription','user_id');
}
we can access subscription details as follows
$users = User:all();
foreach($users as $user){
echo $user->subscription;
}
if any of the user does not have a subscription, which can be a case.
we cannot use arrow function further after subscription like below
$user->subscription->abc [this will not work]
$user->subscription['abc'] [this will work]
but if the user has a subscription
$user->subscription->abc [this will work]
NOTE: try putting a if condition like this
if($user->subscription){
return $user->subscription->abc;
}
It happen that after some time we need to run
'php artisan passport:install --force
again to generate a key this solved my problem ,
I had also this problem. Add code like below in the related controller (e.g. UserController)
$users = User::all();
return view('mytemplate.home.homeContent')->with('users',$users);
Laravel optional() Helper is comes to solve this problem.
Try this helper so that if any key have not value then it not return error
foreach ($sample_arr as $key => $value) {
$sample_data[] = array(
'client_phone' =>optional($users)->phone
);
}
print_r($sample_data);
Worked for me:
{{ !empty($user->role) ? $user->role->name:'' }}
In my case the problem was in wrong column's naming:
In model Product I've tried to access category relationship instance to get it's name, but both column name and relationship had the same name:
category
instead of:
category_id - for column name
category - for relationship
Setting up key name in relationship definition like
public function category():hasOne
{
return $this->hasOne(Category::class,'category');
}
didn't help because as soon as Laravel found property named category gave up on looking for relationship etc.
Solution was to either:
change property name (in model and database) or
change relationship name (Eg. productCategory )
It wasn't an error in my case. However, this happened to me when I was trying to open users.index, because while testing I've deleted some data from the 'STUDENTS' table and in the 'USERS' table, a foreign key ('student_id') represents the 'STUDENTS' table. So, now when the system tries to access the 'USERS' table in which foreign key ('student_id') is null since the value got deleted from the 'STUDENTS' table.
After checking for hours when I realise this, I insert the same data again in the 'STUDENTS' table and this resolved the issue.

Categories