I'm working on a laravel project. I have to join two models Products and User. Where I need to get the results of a product as well as the details of the user who added it. I wrote the code below which isn't working. I'm wondering what'd be the solution.
Can anyone help me in fixing the issue?
Products
class Products extends Model implements AuditableContract
{
use SoftDeletes;
use Auditable;
protected $table = 'products';
protected $fillable = ['product', 'active_ingredient', 'brand', 'similar_to1', 'similar_to2', 'similar_to3', 'similar_to4', 'category_id', 'unit', 'jug_size', 'pallet_qty', 'tote_size', 'class', 'pallet_length', 'pallet_width', 'pallet_height', 'tote_length', 'tote_width', 'tote_height', 'pallet_avg_wt', 'restricted', 'hazmat', 'hazmat_notes', 'market_avg', 'quickbooks_id', 'trending', 'added_by', 'removed_by', 'deleted_at'];
public function productUser()
{
return $this->hasOne('App\User', 'id');
}
}
User
<?php
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use OwenIt\Auditing\Auditable;
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable implements AuditableContract
{
use HasApiTokens, Notifiable;
use SoftDeletes;
use Auditable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
protected $fillable = ['first_name', 'last_name','email','phone','device_token','password','approved','added_by','removed','removed_by','deleted_at'];
public function userProduct(){
return $this->belongsTo('App\Products', 'added_by');
}
}
You need the relation of the Products model to be linked to the user so you create this inside the products model.
You have to modify this:
public function productUser()
{
return $this->hasOne(User::class , 'id', 'added_by');
}
Where user_id is the foreign key in the Products table of the user and id is the primary key in the users table
Then to use that you simple do:
Products::with('productUser')->get();
That will retrieve all products with the user who added each product.
Since you want to retrieve the Products with the user info the function should be written inside the Products model.
The one you have in your user model is irrelevant for what you are trying to achieve so you can remove it.
Product belong to a user and user will have products.
in products
function productUser(){
return $this->belongsTo(User::class, "added_by", "id");
}
in users for one to many relation
function products(){
return $this->hasMany(Product::class, "added_by", "id");
}
if the relation is one on one then it should be like
function product(){
return $this->hasOne(Product::class, "added_by", "id");
}
To get the products with their respective users
$products = Products::whereDate('created_at', Carbon::today())->with('productUser')->get();
Related
I have two table (three actually, but in this context it's only related to these two tables), Pekerjaan and User. Both table are in eloquent. User hasMany pekerjaans, and Pekerjaan belongsTo User. In the User table it has status 'super' and 'ppk'. 'Super' is a super admin whereby it can view all data, and for 'ppk' it can only view certain data based on his/her USER_ID in Pekerjaan's table. Here is my code for User.php model:
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Database\Eloquent\Model as Eloquent;
class User extends Authenticatable
{
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'name',
'email',
'username',
'satker',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
'two_factor_recovery_codes',
'two_factor_secret',
];
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = [
'profile_photo_url',
];
public function pekerjaans(){
return $this->hasMany(Pekerjaan::class);
}
}
And here is the Pekerjaan.php model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model as Eloquent;
class Pekerjaan extends Eloquent
{
use HasFactory;
protected $guarded = [];
public function penyedia(){
return $this->belongsTo(Penyedia::class, 'penyedia_id');
}
public function user(){
return $this->belongsTo(User::class, 'user_id');
}
}
Here is what I've tried in AdminController:
public function tabelpekerjaan(User $user){
if(Auth::user()->status=='super'){
$pekerjaan = Pekerjaan::with('penyedia')->paginate();
return view('admin.datapekerjaan', compact('pekerjaan'));
}else{
$pekerjaan = $user->pekerjaans;
return view('admin.datapekerjaan', compact('pekerjaan'));
}
}
Here is my code in web.php:
Route::get('/datapekerjaan',[AdminController::class,'tabelpekerjaan'])->name('datapekerjaan');
For now it shows me blank table when I logged in as 'ppk', and what I need is it will shows list of pekerjaan based on the user id. How to achieve this? Here is my table pekerjaans in database:
public function tabelpekerjaan(){
if(Auth::user()->status=='super'){
$pekerjaan = Pekerjaan::with('penyedia')->paginate();
return view('admin.datapekerjaan', compact('pekerjaan'));
}else{
$pekerjaan = Auth::user()->pekerjaans;
return view('admin.datapekerjaan', compact('pekerjaan'));
}
}
Try the above code, i guess your route model binding is in correct.
I'm building a Laravel 8 API and want to automatically join user_settings onto a user whenever the User model is queried.
My thinking is that I can achieve this with the belongsTo relationship since user_settings "belongs" to a user.
However, when I attach this to my UserSetting model and query a user I'm not seeing any user settings attached to my User despite having data in the user_settings table.
Where am I going wrong?
Model: User
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class UserSetting extends Model
{
use HasFactory, SoftDeletes;
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'user_settings';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'user_id',
'theme',
'refreshButtonPlacement',
'animationSpeed',
'fetchTimeout'
];
/**
* Get the user that owns the comment.
*/
public function user()
{
return $this->belongsTo(UserSetting::class);
}
}
Model: User
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable, SoftDeletes;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'first_name',
'last_name',
'email',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password'
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
'last_login_at' => 'datetime'
];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* #return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
I also tried using a One To One relationship and defined a settings method on my User model but in Tinker when I ran User::findOrFail(1)->settings; I had nothing either.
Relationship setup:
class User extends Model
{
//some custom stuff
/**
* Get the phone associated with the user.
*/
public function user_setting()
{
return $this->hasOne(UserSetting::class);
}
}
class UserSetting extends Model
{
//some custom things
/**
* Get the user that owns the comment.
*/
public function user()
{
return $this->belongsTo(User::class);
}
}
Afterwards you can use eager laoding by default, in your case you will have to add $with = ['user_setting'] to your User class.
You could also use the ->with() method, for that you will have to use either:
User::with('user_setting')->find(Auth::id());
//or
Auth::user()->with('organisation')->first()
Laravel doesn't load the relationship values in every call because of the obvious overhead. So you will either define the relationship to be loaded by default or you will have to work with the ->with() method for eager loading the relationship.
Add this method to your User model
And you can access the user settings through a dynamic attribute $user-> user_setting
on each User model instance
For more informations
https://laravel.com/docs/8.x/eloquent-relationships#one-to-one
public function user_setting(){
return $this->hasOne(UserSetting::class);
}
I am building a forum website using Laravel and Vue.
I have three tables: forums, posts, and users.
One forum can have multiple posts, each post has a user who created the post.
When the user clicks on one forum, I want to display the latest 10 posts to this forum with the paginate method.
Forum.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Forum extends Model {
use HasFactory;
protected $table = 'forums';
protected $guarded = [];
/**
* Get the forum posts
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function posts() {
return $this->hasMany(Post::class)->orderBy('created_at', 'DESC');
}
}
Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model {
use HasFactory;
protected $table = 'posts';
protected $guarded = [];
/**
* Get the post's user
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user() {
return $this->belongsTo(User::class);
}
}
User.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable {
use HasFactory, Notifiable;
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Get the user posts
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function posts() {
return $this->hasMany(Post::class);
}
}
Here I retrieve the forum posts with the users.
ForumService.php
<?php
namespace App\Services;
use App\Models\Forum;
class ForumService {
public static function getForumPosts($forumId) {
$forum = Forum::with('posts.user')->find($forumId);
dd($forum);
}
}
However, I want to retrieve only 10 posts and get each post's user, so how do I do that in a relationship? The posts are paginated, but how to I get now the posting user? Because the dot syntax is applying to the user, therefore I paginate the user, not the posts.
ForumService.php
<?php
namespace App\Services;
use App\Models\Forum;
class ForumService {
public static function getForumPosts($forumId) {
$forum = Forum::with(
[
'posts' => function ($query) { // How do I get the post user?
return $query->paginate(10);
}
]
)->find($forumId);
dd($forum);
}
}
Just add the with method inside the query scope of the function you have created.
$forum = Forum::with(
[
'posts' => function ($query) {
// returns posts with user
return $query->with('user')->paginate(10);
}
]
)->find($forumId);
Now you can access the first user with $forum->posts[0]->user which will not query to the database but will prefetch the users and populate it in paginator collection.
As you have already the id of the forum you can only retrieve posts which belongs to that Forum and paginate them like this
public static function getForumPosts($forumId) {
return Forum::find($forumId)->posts()->paginate(10);
}
If you want to eager load Post creator you can perform that like this
public static function getForumPosts($forumId) {
return Forum::find($forumId)->posts()->with(['user'])->paginate(10);
}
I have created a relationship between User model and StoryModel. But it give me the Error:-
Call to undefined relationship [userStories] on model [App\User].
May be I'm missing something. Following is my code which I'm using
User.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Notification;
use App\CheckIn;
use App\Travel;
use Carbon\Carbon;
use App\NewInterest;
use App\UserStory;
class User extends Authenticatable
{
use Notifiable;
protected $table = "users";
protected $primaryKey = 'id';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'firstname','lastname', 'user_id','email',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function userStories(){
return $this->hasMany(UserStory::class, 'user_id', 'user_id');
}
}
Controller Logic
$usersStories = User::with('userStories')
->select('id','user_id','stories')
->get();
print_r($usersStories);
exit;
Are you wriiten mapping code in your UserStory Model that should be
public function userAccount(){
return $this->belongsTo(User::class);
}
If you already written this code then check you column names in your DB.
Can you try by changing the sequence like this:
$usersStories = User::->select('id','user_id','stories')
->with('userStories')
->get();
print_r($usersStories);
exit;
You should update your model and try:
User model
public function userStories(){
return $this->hasMany(UserStory::class);
}
UserStory model
public function users(){
return $this->belongsTo(User::class, 'user_id');
}
I'm creating a school platform where students, teachers,... can login using their credentials. To reduce duplicate data I did not make a separate table called students, instead I keep all the data in the users table.
To know if a user is a student I a have a table that is called enrolments, in this table a user_id , schoolyear_id and class_id is stored.
I already made a student model that refers to the users table, but how can I ensure that this model only passes students?
EER:
Student.php:
<?php
namespace App;
class Student extends User
{
protected $table= 'users';
public function enrollments(){
return $this->belongsToMany(Enrollment::class);
}
}
User.php:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Support\Facades\Auth;
class User extends Authenticatable
{
use Notifiable;
use HasRoles;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'first_name','last_name', 'password'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function profiles(){
return $this->hasOne(Profile::class);
}
}
What I want to achieve is that when I call the Student::all(); function I get all the users who are enrolled in the school,hence students.
Check out model events: https://laravel.com/docs/5.5/eloquent#events
You should be able to drop this into your student model for a test:
protected static function boot(){
parent::boot();
static::retrieved(function($thisModel){
if($thisModel->isNotAStudent or whatever logic you need){
return false;
}
}
}
I'm still on 5.4, which does not have the retrieved model event built in, but returning false generally stops the call from going through. So applying that logic to the retrieved event may stop that model instance from being returned if it is not a student, but allow students to be returned. Just a thought.
Your provided solution lead me in the right direction. My problem is solved by using global scope:
<?php
namespace App;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
class Student extends User
{
protected $table= 'users';
protected static function boot()
{
parent::boot();
static::addGlobalScope('student', function (Builder $builder) {
$builder->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('enrollments')
->whereRaw('enrollments.user_id = users.id');
});
});
}
public function enrollments(){
return $this->belongsToMany(Enrollment::class);
}
}