I'm experimenting with relations in Laravel and I cannot figure this one out.
I have two tables users and vehicles. The users can drive a vehicle and the drivers are replaced often. To track these changes I created a history table. This table contains user_id, vehicle_id, start and end.
I want to get the vehicle that the current user is driving, through the History table.
class User extends model {
public function vehicle()
{
// return the current active vehicle for the user
// through the History model.
return $this->hasOne(History::class, 'user_id');
}
public function history()
{
// return all the vehicles that the user has used
// this currently returns the history rows, not the cars
return $this->hasMany(History::class, 'user_id');
}
}
class Vehicle extends model {
public function user()
{
// return the current active user
}
public function users()
{
// return all the users that used this vehicle
}
}
If I perform the following method in a controller.
public function showUser()
{
return User::findOrFail(1)->with('vehicle', 'history')->get()
}
I want the response formatted like the following:
[
0: {
first_name: 'John',
...
vehicle: {
model: 'BMW ...'
}
history: {
0: {
model: 'BMW ...'
}
1: {
model: 'Audi ...'
}
...
}
}
]
You could add a query scope to your history model to return the latest record.
public function scopeLatest($query)
{
return $query->orderBy('created_at', 'desc')->limit(1);
}
Then you can get that through your relationship
$user->history()->latest()->first()->vehicle;
This, of course, requires that you have the vehicle relationship defined in your history class.
Related
I have a database setup where you have a lecturer having many groups and each group having many students and also a student can be in many groups. Therefore I have a one to many relationship between a lecturer and groups (respectively) and a many to many relationship between students and groups.
I want to show the lecturer how many students they have overall. For example if the lecturer has 5 groups with 5 students in each then I want to show 25. I tried this auth()->user()->userable->groups()->withCount('students') but I got this:
Call to a member function getRelationExistenceCountQuery() on null
Edited, Here are the relationships:
# user model
class User extends Authenticatable{
public function userable(){
return $this->morphTo();
}
}
# staff/lecturer model
Staff extends Model {
public function user(){
return $this->morphOne(User::class, 'userable');
}
public function groups(){
return $this->hasMany(Group::class);
}
}
#group model
class Group extends Model {
public function staff(){
return $this->belongsTo(Staff::class);
}
public function students(){
$this->belongsToMany(Student::class, 'groups_students', 'group_id');
}
}
# student model
class Student extends Model {
public function groups(){
return $this->belongsToMany(Group::class, 'groups_students', 'student_id');
}
}
What's the most efficient way to get my desired result?
Group::students() is missing the return statement:
public function students(){
return $this->belongsToMany(Student::class, 'groups_students', 'group_id');
^^^^^^
}
You can get the total of number of students like this:
$groups = auth()->user()->userable->groups()->withCount('students')->pluck('students_count');
$count = $groups->sum();
I'd like to establish a many to many polymorphic relation in Laravel. (I'm new to it)
A user can have many profile types
Profile types are like Admin, Webmaster, ProjectManager.
I created a polymorphic relation and a pivot table for the profiles.
class User {
public function profiles(){
return Profile::where('user_id', $this->id);
}
}
class Webmaster { // and class Admin, Projectmanager
public function profiled(){
return $this->morphToMany(Profile::class, 'profileable');
}
public function saveToUser($user)
{
$profile = new Profile;
$profile->user_id = $user->id;
return $this->profiled()->save($profile);
}
}
Now I can save the models to the corresponding User.
$projectManager->saveToUser($user);
$webmaster->saveToUser($user);
It gets all saved to the pivot table as expected and the relations are valid.
profiles table looks like this:
id
user_id
profilable_id
profilable_type
Now the problem is retrieving a model collection of my profiles. I get the Profile types, but I dont get the Webmaster and ProjectManager.
So the question is: how do I get this model collection in this example?
Your model structure is going to be like:
class Webmaster extends Model
{
public function users()
{
return $this->morphToMany('App\Profile', 'userable');
}
}
class Admin extends Model
{
public function users()
{
return $this->morphToMany('App\Profile', 'userable');
}
}
// and ProjectManager, ....
User Model:
class User extends Model
{
public function webmasters()
{
return $this->morphedByMany('App\Webmaster', 'userable');
}
public function admins()
{
return $this->morphedByMany('App\Admin', 'userable');
}
}
Database schema:
webmasters
id - integer
...
admins
id - integer
...
users
id - integer
...
userables
user_id - integer
userable_id - integer
userable_type - string
Now, you can retrieve the relations:
$webmaster = App\Webmaster::find(1);
// retrieve users of a profile
foreach ($webmaster->users as $user) {
//
}
$user = App\User::find(1);
// retrieve webmaster profiles of a user
foreach ($user->webmasters as $webmasters) {
//
}
Actually, your profiles (webmaster, admin, projectmanager) are userable.
I have the following model relationships. If a user logs in as an employee, I want them to be able to get a list of employees for a their company and the roles they have been assigned:
class User {
// A user can be of an employee user type
public function employee()
{
return $this->hasOne('App\Employee');
}
//
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
class Employee {
// employee profile belong to a user
public function user()
{
return $this->belongsTo('App\User');
}
// employee belongs to a company
public function company()
{
return $this->belongsTo('App\Company');
}
}
class Company {
public function employees()
{
return $this->hasMany('App\Employee');
}
}
But the following query doesnt work. I get error Column not found: 1054 Unknown column companies.id in WHERE clause:
$employee = Auth::user()->employee;
$companyEmployees = Company::with(['employees.user.roles' => function ($query) use ($employee) {
$query->where('companies.id', '=', $employee->company_id)
->orderBy('users.created_at', 'desc');
}])->get();
The users and the employees table have a one to one relationship.
All employees have a base role type of employee in addition they may also have other roles such as manager, supervisor etc.
How do I write a query that gives me a company with all its employees and their roles?
I've tried to add a hasManyThrough relation to the Company model but that doesn't work either?
public function users()
{
return $this->hasManyThrough('App\User', 'App\Employee');
}
I think you're ring to get a list of coworkers for the current user and eager load the user and role?
$employee = Auth::user()->employee;
$companyEmployees = Company::with(['employees.user.roles')->find($employee->company_id);
Or perhaps:
$companyEmployees = Company::find($employee->company_id)->employees()->with('user.roles')->get();
$sorted = $companyEmployees->sortBy(function($employee){ return $employee->user->created_at; });
That might be a more direct route. Is your employee id in the user table or vice versa? The eloquent relationships are easy to set backwards.
Users::select('table_users.id')->with('roles')->join('table_employes', function($join) use ($employee) {
$join->on('table_employes.user_id','=','table_users.id')->where('table_employes.company_id', '=', $employee->company_id);
})->orderBy('tables_users.created_at')->get();
1. Create relationship for database table columns in migrtaion :
User Role
$table->foreign('user_id')->references('id')->on('users');
Users
$table->increments('id');
2. Create a model for each database table to define relationship
User.php (model)
public function userRoles()
{
return $this->hasOne('App\UserRoles', 'user_id', 'id');
}
Userroles.php (model)
public function user()
{
return $this->belongsTo('App\User', 'user_id', 'id');
}
3. Let controller handle database calls recommended to use REST api
Controller
use App\User;
use App\UserRoles;
class UserController extends Controller
{
public function index()
{
return User::with('userRoles')->orderBy('users.created_at', 'desc')->paginate(50);
}
}
I have three tables: users, items and user_items. A user has many items and a item belongs to many users.
**Users**
id
username
password
**Items**
id
name
**User_items**
id
user_id
item_id
Models:
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items', 'item_id', 'user_id');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id');
}
}
I need to select all items table, print it and highlight rows which belongs to specific user id=1.
Selection highlighted output:
What is the right way to do it (in laravel style)?
You can use it like this
public function user_items()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id')->withPivot('id');
}
Like this you can access values of third table.
Some useful links-
http://www.developed.be/2013/08/30/laravel-4-pivot-table-example-attach-and-detach/
http://vegibit.com/many-to-many-relationships-in-laravel/
http://laravel.com/docs/4.2/eloquent
You can do it like this way...
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items', 'item_id', 'user_id')->withPivot('id');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id')->withPivot('id');
}
}
From controller..
$user_id = 2;
Item::with(['users'=>function($q) use ($user_id){$q->where('user_id',$user_id);}])->get();
In view at the time of listing a row you can highlight the row just use a condition as each item->users is blank or not.
So using Laravel 4, I have a Sales table that has a many to many relationship with a Products table, and it also has a one to many relation with a Customers table.
I set up my models as follows:
class Sale extends Eloquent {
...
public function products(){
return $this->belongsToMany('Product');
}
public function customers(){
return $this->belongsTo('Customer');
}
}
class Product extends Eloquent {
...
public function sales(){
return $this->belongsToMany('Sale');
}
}
class Customer extends Eloquent {
...
public function sales(){
return $this->hasMany('Sale');
}
}
What I want to do is return the data of all sales, including the data of each product included in each sale and the data of the customer that bought it.
In my SalesController I'm using eager loading to query my data like this:
public function index()
{
return Sale::with('products', 'customers')->get();
}
It returns an object with the Sale data, the Product data, but the Customer data is null.
How can I achieve this using Eloquent (or a custom query)?
EDIT
This is the object string it returns:
[{"id":1,"customer_id":1,"date":"2013-11-21","status":1,"created_at":"0000-00-00 00:00:00","updated_at":"0000-00-00 00:00:00","products":[{"id":1,"name":"Monitor","price":50,"status":1,"created_at":"0000-00-00 00:00:00","updated_at":"0000-00-00 00:00:00","pivot":{"sale_id":1,"product_id":1,"custom_price":25,"order":1}}],"customers":null}]
Try changing your customers relationship to singular:
class Sale extends Eloquent {
...
public function products(){
return $this->belongsToMany('Product');
}
public function customer(){ // <- here
return $this->belongsTo('Customer');
}
}
(Moved from comments to answer)