Laravel search based on foreign key from a different table - laravel

I have three tables post,user and country.
Post is saved by user who is from a country.
Now I want to search all posts of all users from a country.
so user will filter by country and I get country code from search box to controller $request->input($country);
Here are my model relationships:
POST MODEL:
class Post extends Model
{
protected $table = 'posts';
protected $dates = ['status_change'];
public function photos()
{
return $this->hasMany(Photo::class,'post');
}
public function make_rel()
{
return $this->belongsTo(Make::class, 'make_id' ,'id','make_logo');
}
public function user_rel()
{
return $this->belongsTo(User::class, 'created_by' ,'id');
}
}
COUNTRY MODEL:
class Country extends Model
{
public function users(){
return $this->hasMany('App\User');
}
}
USER MODEL:
class User extends Authenticatable
{
public function country_rel()
{
return $this->belongsTo(Country::class, 'country' ,'country_code');
}
}
SEARCH FUNCTION
public function search(Request $request)
{
$this->validate($request, [
'country' => 'required',
]);
$country = Country::where('country_name',$request->input('country'))->get();
$data = Post::where('created_by',$country->user_rel->name)
->get();
dd($data);
}
This is not working. Could anyone advise what am I doing wrong?

I would use hasManyThrugh. The documentation even uses your exact use case:
class Country extends Model
{
public function users(){
return $this->hasMany('App\User');
}
public function posts() {
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}

Related

laravel 8 store request with foreign key user_id not working

I would like to store the corresponding logged in user when adding a new School data. What I'm trying to do is store the logged in user_id in the schools table, in order to know on who added the school data. I have a users table already, which will establish the relation in the schools table.
My goal is when an admin is logged in, he/she can see all of the School records, otherwise if it's a user, then only fetch the records he/she added. The problem is that I can't figure out on when and where to insert the user_id data during the store request as I'm getting an error "user id field is required". Here's what I've tried so far:
Migration:
class CreateSchoolsTable extends Migration
{
public function up()
{
Schema::create('schools', function (Blueprint $table) {
$table->id();
$table->string('school_name');
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
}
}
School Model:
class School extends Model
{
use HasFactory;
protected $fillable = ['school_name', 'user_id'];
public function User() {
return $this->belongsTo(User::class);
}
}
Store Request:
class StoreSchoolRequest extends FormRequest
{
public function rules(): array
{
return [
'school_name' => 'required|string|max:255',
'user_id' => 'required|exists:users,id'
];
}
}
Controller:
class SchoolController extends Controller
{
public function store(StoreSchoolRequest $request) {
$school_data = $request->validated();
$user_id = \Auth::user()->id;
$school_data['user_id'] = $user_id;
School::create($school_data );
return Redirect::route('schools.index');
}
}
Any inputs will be of big help! Thanks.
Laravel has elegant way to bind authenticated user_id. Remove user_id from request class and chaining method. Also setup relationship from User model to School Model
Form Request Class
class StoreSchoolRequest extends FormRequest
{
public function rules(): array
{
return [
'school_name' => 'required|string|max:255',
];
}
}
User Model
protected $fillable = ['school_name', 'user_id'];
...
// new line
public function schools() {
return $this->hasMany(School::class);
}
Your Controller
class SchoolController extends Controller
{
public function store(StoreSchoolRequest $request) {
auth()->user()->schools()->create($request->validated());
return Redirect::route('schools.index');
}
}
UPDATE ANSWER
Since user_id value is school name (based on image link from comment), probably there's something wrong either in User or School model. Here the quick fix
Your Controller
class SchoolController extends Controller
{
public function store(StoreSchoolRequest $request) {
auth()->user()->schools()->create(
array_merge(
$request->validated(),
['user_id' => auth()->id()]
)
);
return Redirect::route('schools.index');
}
}
You can add 'created_by' and 'updated_by' fields to your table. so you can register in these fields when additions or updates are made.
Then you can see who has added or updated from these fields.
class School extends Model
{
use HasFactory;
protected $fillable = ['school_name', 'user_id', 'created_by', 'updated_by'];
public function User() {
return $this->belongsTo(User::class);
}
}
Your controller part is correct but since you get the logged in user, you wont be having user_id in the request. So you should remove the rules about user_id from your StoreSchoolRequest.
class StoreSchoolRequest extends FormRequest
{
public function rules(): array
{
return [
'school_name' => 'required|string|max:255'
];
}
}
Problem is here ..
$school_data = $request->validated();
Since you are using $request->validated()..
You have to safe()->merge user_id into it , here Docs : .
$validated = $request->safe()->merge(['user_id' => Auth::user()->id]);
Then put this $validated into create query , Thanks. –

Laravel eloquent multiple levels of relations

Alright so I am basically trying to retrieve all animal_registry codes based on a user ID.
Idea is that
1 user has many jobs.
Jobs are consisted of many "Jobs data".
Jobs data has many "Animal registry" entries.
These are my relations
Image relations link (click)
And these are my relations in Laravel
class User
{
public function jobs()
{
return $this->hasMany('App\Models\RegistryJobs', 'employee', 'id');
}
}
class RegistryJobs extends Model
{
protected $table = "registry_jobs";
protected function jobsData()
{
$this->hasManyThrough('App\Models\AnimalRegistry', 'App\Models\RegistryJobsData', 'id', 'animal_registry_id');
}
}
class RegistryJobsData extends Model
{
protected $table = "registry_jobs_data";
public function jobs()
{
$this->belongsTo('App\Models\RegistryJobs', 'id', 'registry_jobs_id');
}
public function animals()
{
$this->hasMany('App\AnimalRegistry', 'id', 'animal_registry_id');
}
}
class AnimalRegistry extends Model
{
protected $table = "animal_registry";
}
And now I am trying to query it from a controller in a way
$data = User::whereHas('jobs', function ($query) {
$query->where('id', 1);
})->get();
But I am unable to access the properties from the animal_registry.
Can you try like this :
public function animals(){
return $this->hasManyThrough('App\Registry_Jobs_data','App\Registry_Jobs', 'employee',
'registry_jobs_id', 'id' ,'id')->join('//Do the joining')->select();
}
Check the hasManyThrough i am not sure..

Laravel Complex Relationships Through Polymorphism

I have the following models using Laravel 5.3:
Provider:
// Provider model
$primaryKey = 'id'
public function activities()
{
return $this->hasMany(Activity::class);
}
Activity:
// Activity model
$primaryKey = 'id'
public function provider()
{
return $this-belongsTo(Provider::class);
}
public function semesters()
{
return $this->hasMany(Semester::class);
}
public function semesterPurchases()
{
return $this->hasManyThrough(Purchase::class, Semester::class, 'activity_id', 'purchasable_id')
->where('purchasable_type', Semester::class);
}
Semester:
// Semester model
$primaryKey = 'id'
public function activity()
{
return $this->belongsTo(\App\Models\Activity::class, 'activity_id', 'id');
}
Purchase:
// Purchase model
$primaryKey = 'id'
public function purchasable()
{
return $this->morphTo();
}
In my case Semester::class is the purchasable_type. Is there a way to establish a relationship between Provider::class and Purchase::class? In order to make it possible to do something like this:
$providers = Provider::select('id', 'name', 'address')
->with('purchases')
->where('providers.id', 1)
->get();
I would prefer not to go through activities like so:
$providers = Provider::select('id', 'name', 'address')
->with('activities.purchases')
->where('providers.id', 1)
->get();
which I know I can do using hasManyThrough on the Activity::class
Laravel has no native support for a direct relationship.
I've created a package for cases like this: https://github.com/staudenmeir/eloquent-has-many-deep
class Provider extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function purchases()
{
return $this->hasManyDeep(
Purchase::class,
[Activity::class, Semester::class],
[null, null, ['purchasable_type', 'purchasable_id']]
);
}
}
Provider::find($id)->purchases;

nested relation with condition in laravel

I have 3 models
User - Role- Permission
User
class User extends Model
{
protected $fillable = [
'name', 'email', 'password',
];
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
Role
class Role extends Model
{
protected $fillable = ['name' , 'label'];
public function users()
{
return $this->belongsToMany(User::class);
}
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
}
Permission
class Permission extends Model
{
protected $fillable = ['name' , 'label'];
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
I want get List of users whose permissions were updated on a specific date
I know I sould use something like below but I dont know exatly how to use Where
$users = User::with('roles.permissions')->orderBy('name', 'asc')->paginate(25);
thanks alot
Use whereHas():
$users = User::whereHas('roles.permissions', function($query) use($date) {
$query->whereDate('permission_role.updated_at', $date);
})->orderBy('name', 'asc')->paginate(25);

Laravel - Retrieving specific column from a releted query

I have 4 tables:
conversations
- id (pk)
- userId1 (fk)
- userId2 (fk)
users
- id (pk)
- name
- surname
.
.
.
- roleId (fk)
- userStatusId (fk)
roles
- id (pk)
- type (fk)
user_status
- id (pk)
- description (fk)
this are my models:
class Conversation extends Eloquent {
public function user1(){
return $this->hasOne('User', 'id', 'userId1');
}
public function user2(){
return $this->hasOne('User', 'id', 'userId2');
}
}
class User extends Eloquent {
public function role(){
return $this->hasOne('Role', 'id', 'roleId');
}
public function userStatus(){
return $this->hasOne('UserStatus', 'id', 'userStatusId');
}
// public function conversation1(){
// return $this->belongsToMany('Conversation', 'id', 'userId1');
// }
// public function conversation2(){
// return $this->belongsToMany('Conversation', 'id', 'userId2');
// }
}
class UserStatus extends Eloquent {
public $timestamps = false;
protected $table = 'user_status';
public function user(){
return $this->belongsToMany('User', 'id', 'userStatusId');
}
}
class Role extends Eloquent {
public $timestamps = false;
public function user(){
return $this->belongsToMany('User', 'id', 'roleId');
}
}
Now what I want to do is, for example, take all the conversations where the "userId1" (on conversations) is of a "user" who have the status "description" equal to "registered".
That's what I do:
Route::get('/', function(){
$conversation = Conversation::with(array('user1.userStatus' => function ($query){
$query->where('description', '=', 'registered');
}))->get();
foreach ($conversation as $conv) {
echo '<br \>';
echo $conv;
}
});
I expect to receive all the conversations record where the status of the userId1 is "registered" and nothing else... Instead what I receive are all the conversations records and, for each one, the user records and the records of the userStatus table (of this last I receive just the one who match the where clause and the ones who are not have a null value).
I know my english is terrible but I hope someone could understand and help me. Thanks!
All your relations are wrong. You need to read http://laravel.com/docs/eloquent#relationships and in your case it's:
class Conversation extends Eloquent {
public function user1(){
return $this->belongsTo('User', 'userId1');
}
public function user2(){
return $this->belongsTo('User', 'userId2');
}
}
class User extends Eloquent {
public function role(){
return $this->belongsTo('Role', 'roleId');
}
public function userStatus(){
return $this->belongsTo('UserStatus', 'userStatusId');
}
}
class UserStatus extends Eloquent {
public $timestamps = false;
protected $table = 'user_status';
public function user(){
return $this->hasMany('User', 'userStatusId');
}
}
class Role extends Eloquent {
public $timestamps = false;
public function user(){
return $this->hasMany('User', 'roleId');
}
}
Now, to retrieve only those conversations you want this:
Conversation::whereHas('user1', function ($q) {
$q->whereHas('userStatus', function ($q) {
$q->where('description', 'registered');
});
})->get();
or using this PR https://github.com/laravel/framework/pull/4954
Conversation::whereHas('user1.userStatus', function ($q) {
$q->where('description', 'registered');
})->get();
Also, to make it more verbose, you can wrap that code in a scope:
// User model
public function scopeRegistered($query)
{
$q->whereHas('userStatus', function ($q) {
$q->where('description', 'registered');
});
}
then:
Conversation::whereHas('user1', function ($q) {
$q->registered();
})->get();
You may try this:
$conversations = Conversation::whereHas('user1.userStatus', function ($query){
$query->where('description', '=', 'registered');
})->get();
This will return only the Conversation models whose related user1.userStatus is registered.

Resources