How to retrieve Nested Relationship data in laravel 5 using eloquent? - laravel-5

Having some problems retrieving nested relationship data. Here are my models:
class Partner extends Model
{
public function admins()
{
return $this->hasMany(Resource::class)->where('resource_type', 'Admin');
}
}
class Resource extends Model
{
public function details() {
return $this->belongsTo(ResourceDetail::class);
}
}
class ResourceDetail extends Model
{
}
When I try $this->partner->admins[0]->details it's giving null. The sql it generated is: "select * from resource_details where resource_details.id is null". I'm not quite sure why is it null in the query. I must have done something wrong with the relations. I tried $this->partner->with('admins.details')->find($this->partner->id)->toArray();. It's getting the admins, but details is still null. I also tried hasManyThrough, like: return $this->hasManyThrough(ResourceDetail::class, Resource::class)->where('resource_type', 'Admin'); it finds "unknown column". This is my database structure:
Schema::create('partners', function (Blueprint $table) {
$table->increments('id');
});
Schema::create('resources', function (Blueprint $table) {
$table->increments('id');
$table->integer('partner_id')->nullable()->unsigned();
$table->foreign('partner_id')->references('id')->on('partners')
->onUpdate('cascade')->onDelete('set null');
$table->enum('resource_type', constants('RESOURCE_TYPES'))->nullable();
$table->integer('resource_detail_id')->unsigned();
$table->foreign('resource_detail_id')->references('id')->on('resource_details')
->onUpdate('cascade')->onDelete('cascade');
});
Schema::create('resource_details', function (Blueprint $table) {
$table->increments('id');
});
Do I need to change the structure? Or, how can I get the data from current structure? All I want is, a partner has many resources, and a resource has one details.

From that error I think you may be trying to call $this->partner->admins[0]->details from a model that doesn't have an id. What is $this in context to?

Related

Laravel creates a one-to-many relationship instead of one-to-one

When I create a one-to-one relationship migration, laravel creates a one-to-many relationship. I tried to solve this in different ways and nothing worked.
How can I solve this?
Company:
class Company extends Model
{
public function user()
{
return $this->hasOne(User::class);
}
...
}
User:
class User extends Authenticatable
{
public function company(){
return $this->belongsTo(Company::class);
}
...
}
Migrations:
Schema::create('Company', function (Blueprint $table) {
$table->mediumIncrements('idCompany');
...
});
Schema::create('User', function (Blueprint $table) {
$table->id();
$table->increments('idUser');
$table->unsignedMediumInteger('Company_idCompany')
->unique()
->nullable();
$table->foreign('Company_idCompany')
->references('idCompany')
->on('company')
->onDelete('set null');
...
});
Laravel is creating nothing (on the migration), you always have to manually create the Model relationship (you are using hasOne and belongsTo, so that is 1-to-1) and migrations (you are creating User and Company not following the standards).
So, update your migrations to:
Schema::create('company', function (Blueprint $table) {
$table->id();
...
});
Schema::create('user', function (Blueprint $table) {
$table->id();
$table->increments('user_id');
$table->foreignId('company_id')
->unique()
->nullable();
$table->foreign('company_id')
->references('id')
->on('company')
->onDelete('set null');
...
});
See that I have moved everything to lowercase and snake case, remember to follow Laravel conventions or you are going to have a harder time working with Models...
Then, your relationships are correct:
class Company extends Model
{
public function user()
{
return $this->hasOne(User::class);
}
...
}
class User extends Authenticatable
{
public function company(){
return $this->belongsTo(Company::class);
}
...
}
So, when you do access a relationship, it will work out of the box now.
If you do Company::first()->user, that will return User or null, and if you do User::first()->company, that will return Company or null, there is no 1-to-N.

Do i need a One-to-Many polymorphic relationship?

I've got a problem i can't get through, here are my models:
Cloth.php​
public function selling(): BelongsTo
{
return $this->belongsTo(Selling::class);
}
Selling.php​
public function clothes(): HasMany
{
return $this->hasMany(Cloth::class);
}
​And now it's anything ok and pretty basic... but then came this model:
Accessory.php​
public function selling(): BelongsTo
{
return $this->belongsTo(Selling::class);
}
And now it's the problem: I need (i think) a polymorphic relationship but i can't understand how to make it in this specific case.
I have 2 starting models to morph to 1 model but every example i found have 1 starting model to morph to 2 models.
Do i need a polymorphic relationship?
I can't really get out of this.
Thanks!
You are basically looking for a one to many polymorphic relationship. Here is how to do it:
Let's say your tables are structured like bellow;
Schema::create('sellings', function (Blueprint $table) {
$table->id();
$table->integer('relation_id');
$table->string('relation_type');
$table->timestamps();
});
Schema::create('accessories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('details');
$table->timestamps();
});
Schema::create('cloths', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('description');
$table->timestamps();
});
Selling.php
public function relation(){
return $this->morphTo();
}
Cloth.php
public function selling(){
return $this->morphOne(Selling::class, 'relation');
}
Accessories.php
public function selling(){
return $this->morphOne(Selling::class, 'relation');
}
Then, you can query using bellow approach;
$selling = Selling::findOrFail(1)->relation;
Now when you dd($selling) you get exactly what you are looking for from a correspondent table;
Please remember that the relation_type field needs to exactly correspond the model. See bellow screenshot for example;
What happens here is when you create a polymorphic function called test the database fields need to follow with test_type corresponding to model and test_id corresponding to the id of the model/database table.

Selecting from multiple tables in laravel

please help.I have a test booking table that looks like this
Schema::create('test_bookings', function (Blueprint $table) {
$table->unsignedInteger('RequestID');
$table->string('bookingDate');
$table->string('timeSlot');
$table->unsignedInteger('nurse_id');
$table->timestamps();
});
and a tests table that looks like this
Schema::create('tests', function (Blueprint $table) {
$table->unsignedInteger('RequestID');
$table->unsignedInteger('patientID');
$table->string('barcode');
$table->string('temperature');
$table->string('pressure');
$table->string('oxygen');
$table->unsignedInteger('nurseID');
$table->timestamps();
});
I want to show the RequestID,bookingDate,timeSlot, name and surname of the nurse only if the test_bookings RequestID is in tests table. This is my nurse table
Schema::create('nurses', function (Blueprint $table) {
$table->unsignedInteger('nurseID');
$table->string('name');
$table->string('surname');
$table->string('idNumber');
$table->string('phone');
$table->string('email');
$table->unsignedInteger('suburb_id');
$table->timestamps();
$table->index('suburb_id');
});
This is the code that i tried
$tests = DB::table('tests')
->select('RequestID','bookingDate','timeSlot','name','surname')
->join('nurses','nurses.nurseID','test_bookings.nurse_id')
->join('test_bookings','test_bookings.RequestID','=','tests.RequestID')
->get();
but when I join the tests table nothing is showing
that because you are using join clause that generate innerJoin statement, and to see the results you should use leftJoin
$tests = DB::table('tests')
->select('RequestID','bookingDate','timeSlot','name','surname')
->leftJoin('nurses','nurses.nurseID','=','test_bookings.nurse_id')
->leftJoin('test_bookings','test_bookings.RequestID','=','tests.RequestID')
->get();
Why you're not using ORM here, a simple one-to-one relationship can do the job perfectly. Here is an example:
class TestBooking extends Model {
# Other code...
public function nurse(){
return $this->belongsTo(Nurse::class);
}
}
class Test extends Model {
# Other code...
public function testBooking(){
return $this->belongsTo(TestBooking::class, 'RequestID','RequestID');
}
}
Now you can get all data like this:
$tests = Test::with("testBooking","testBooking.nurse")->get();
// and get data inside loop like this:
$test->RequestID // to get request ID
$test->testBooking->bookingDate // to get booking date
$test->testBooking->timeSlot // to get timeSlot
$test->testBooking->nurse->name // to get nurse name
$test->testBooking->nurse->surname // to get nurse surename
To know more about relationships read documention.

OrderBy With relationships

I have a comments table which in turn can contain replies to comments via the parent_id table.
Attached, is the migration
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->string('comment');
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('commentable_id');
$table->string('commentable_type');
$table->unsignedBigInteger('parent_id')->nullable();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('parent_id')->references('id')->on('comments')->onDelete('cascade');
$table->timestamps();
});
Attached, Model Relationship
public function replys()
{
return $this->hasMany(Comment::class, 'parent_id');
}
I would like to bring all comments and their replies sorted by id desc.
This way I get the parents back correctly but I need to sort the replys as well.
$comments = $this->post->comments()->with('user', 'replys')->get();
$comments = $comments->sortByDesc('id')->values()->all();
How should I do it? thank you very much
I think it's possible to do it in 2 ways:
1 - You can add an orderBy method directly to the relation
public function replys()
{
return $this->hasMany(Comment::class, 'parent_id')->orderBy('created_at');
}
2 - You can chain the orderBy Method on a controller or wherever you're using the relation.
class Controller
{
public function index()
{
$replies = Model::find(1)->replys()->orderBy('created_at')->get();
}
}
Please, try this solution and check if it works for you!

Laravel hasOne (one to one relationship)

I am trying to learn Laravel-> one to one relationship.
In given code link(join) should be dependent on name(user2s table) and title(post2s table) but the link(join) is dependent on my_id(user2s table) and title(post2s table)
My full codes
Migrations:-
user2s table
Schema::create('user2s', function (Blueprint $table) {
$table->increments('my_id');
$table->string('name');
$table->string('email');
$table->string('password');
$table->string('remember_token');
$table->timestamps();
});
post2u table:
Schema::create('post2s', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('title');
$table->text('content');
$table->timestamps();
$table->tinyInteger('is_admin');
});
Model User2
protected $primaryKey = 'my_id';
public function postx(){
return $this->hasOne(Post2::class, 'title', 'name');
}
My Route Code
Route::get('user/{id}/post', function($id){
return User2::find($id)->postx;
});
http://localhost:8000/user/abc/post
error: Trying to get property of non-object
user2s table
post2s table
Let me explain what is your issue.
error: Trying to get property of non-object, it means it can't find the result. The result object is null, so when you looking for null->postx, it can't get them anything.
You search for User2::find($id), when you use find(), it is looking for primary key. And you User2 Model primary key is my_id, and you are looking for Post2->title. It not able to find it.
More infor about find()
https://laravel.com/docs/5.5/eloquent#retrieving-single-models
Since you are looking for the Post2 title. And you are referencing from User2. It is not correct.
What you should do is
In your route.php
Route::get('user/{title}/post', function($title){
//return Post2::all();
$post = Post2::with('userx')->where('title', $title)->first();
dump($post);
dump($post->userx)//<- you can get user info via
});
In Post2 Model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post2 extends Model
{
public function userx(){
return $this->belongsTo(User2::class, 'user_id');
}
}

Resources