laravel Eloquent one to many same object - php

ok I have this table "areas":
id -> primary key, int
parent -> int, index, nullable
areaName -> string
this table contains areas, and each area can be a son of another area, so the parent column could be null, or another id of any other area.
now I want to make it accessible with Eloquent, this is an one to many relationship.
I tried this code but not so good, any ideas from someone who done something like this?
class Area extends Eloquent {
public function sons() {
return $this->hasMany('Area', 'id', 'parent');
}
public function parent() {
return $this->belongsTo('Area');
}
}

If I am not wrong and from the given code, Laravel complains about area_id column is not found, am I right?
This happens because you do not provide name of foreign column and Laravel tries to guess it for you.
Change relationship definition to this
public function parent() {
return $this->belongsTo('Area', 'parent');
}

I fount the solution, it works great for me.
class Area extends Eloquent {
public function subAreas() {
return $this->hasMany('Area', 'parent', 'id');
}
public function parentArea() {
return $this->belongsTo('Area', 'parent', 'id');
}
}

Related

how to make relation between two tables in laravel

I tried all the tutorials on internet and Youtube but it doesn't work so you guys are my last chance please I need your help.
I need to use $candidate->service->service_name
and $candidate->documents->doc but it doesn't work
I get this error [Call to undefined method stdClass::service()] (by the way, should I use"documents" or "document" ?)
the "candidate" has more than one document, and the document belongs to only one "candidate";
the "candidate" has to choose one "service" (to work in) and the service is chosen by a lot of "candidate"
I have 3 tables :
services=['id_service',
'service_name'] #((id_service Primary key))
candidate =[ 'id_candidate',
'id_service',
'name',
'email'...]; #((id_candidate Primary key, id_service Foreign key))
document=['id_doc',
'id_candidate',
'doc'] #((id_doc Primary key, id_candidate Foreign key))
IN CANDIDATE'S MODEL :
use App\Models\Service;
use App\Models\Document;
public function documents()
{
return $this->hasMany(Document::class);
}
public function service()
{
return $this->belongsTo(Service::class);
}
IN DOCUMENT'S MODEL :
use App\Models\Candidate;
public function candidate()
{
return $this->belongsTo(Candidate::class, 'id_candidate', 'id_doc');
}
IN SERVICE'S MODEL :
use App\Models\Candidate;
public function candidates()
{
return $this->hasMany(Candidate::class);
}
IN CANDIDATECONTROLLER :
public function show( $id_candidate)
{
$candidate = DB::table('candidates')->select('id_candidate','id_service','name')->where('id_candidate', $id_candidate)->first();
return view ('candidate.profile', compact('candidate'));
}
IN candidate/profile :
...
<input type="text" id="service" name="service" value={{ $candidate->service()->service_name }}>
You're my hope
Thank you in advance
Candidate Model
class Candidate extends Model
{
public function candidate_documents()
{
return $this->hasMany(Document::class, 'id_candidate');
}
public function candidate_service()
{
return $this->BelongsTo(Service::class, 'id_service');
}
}
By using DB:: relationships do not work as commented by #ceejayoz
so from candidate controller you can used it like this
$candidateResult= Candidate::with('candidate_documents')->with('candidate_service')->get();
you can also use hasOne in candidate_service() depends on where is your foreign key is
In your code, Candidate has a id_service column, then candidate belongsTo Service.
by using hasOne and hasMany we are telling laravel that this table does not have the foreign key.

Laravel Eloquent getting data from relations

I have Task model. My Task model has some relationships and it currently looks like this:
class Task extends Model
{
use HasFactory;
public $timestamps = false;
public function city()
{
return $this->hasOne(City::class, 'id', 'city_id');
}
public function type()
{
return $this->hasOne(Type::class, 'id', 'type_id');
}
public function note()
{
return $this->hasOne(Note::class, 'id', 'note_id');
}
public function operator()
{
return $this->hasOne(User::class, 'id', 'operator_id');
}
}
Now, in my TasksController I need to get Tasks that match certain criteria, like this:
$tasks = Task::whereCityId($city->id)->whereTypeId($type->id)->get()->toArray();
The problem is that fields named city_id type_id note_id operator_id will get my integer values that they have.
Instead I would like to get certain value from a related Model.
For example:
operator_id should be replaced with username from User table that corresponds to the user id.
An obvious solution to this would be to simply use foreach loop, go through my results and get the data I need and simply create another array with the information replaced, but I am not sure if this is the best idea and perhaps there is something better.
You have to change in your code:
$this->hasOne(ClassName::class, 'id', 'foreign_key');
To
$this->belongsTo(ClassName::class, 'foreign_key', 'id');
because Task's id does not available as foreign key in these tables. These table's id present in task table as foreign key so you have to use belongsTo() relationship to tell script from where these id belongs.
Then access properties like this:
$tasks = Task::with("type", "city", "operator")
->whereCityId($city->id)->whereTypeId($type->id)->get();
foreach($tasks as $task){
echo $task->city->name;
}
first you should fix your relation:
public function city()
{
return $this->hasOne(City::class,'city_id','id');
}
and so one the same error, foreign key in argument order comes before the primary key.
after that you can use addSelect:
$tasks = Task::whereCityId($city->id)->whereTypeId($type->id)
->addSelect(['userName' => User::select('name')
->whereColumn('users.id', 'tasks.operator_id')
->limit(1)])->get()->toArray();
i think this will help better than what you ask.
$tasks = Task::whereCityId($city->id)
->whereTypeId($type->id)
->with('operator')
->get()->toArray();
with('operator') is ORM feature that make you collection to include its relation as collection property. In this case it will convert to array property.
you could access it from your foreach function as
#foreach($task as $key)
$key['operator']['username']
#endforeach
Have a nice day

use relationship in model accessor in laravel

Suppose I have a Course model like this :
class Course extends Model
{
public $primaryKey = 'course_id';
protected $appends = ['teacher_name'];
public function getTeacherNameAttribute ()
{
$this->attributes['teacher_name'] = $this->teacher()->first()->full_name;
}
public function teacher ()
{
return $this->belongsTo('App\User', 'teacher', 'user_id');
}
}
And in the other hand there is a User model like this :
class User extends Authenticatable
{
public $primaryKey = 'user_id';
protected $appends = ['full_name'];
public function getFullNameAttribute ()
{
return $this->name . ' ' . $this->family;
}
public function course ()
{
return $this->hasMany('App\Course', 'teacher', 'user_id');
}
}
As you can see there is a hasMany relationship between those.
There is an full_name accessor in User model.
Now I want to add a teacher_name accessor to Course model that uses it's teacher relations and gets full_name of teacher and appends to Course always.
In fact I want whenever call a Course model, it's related teacher name included like other properties.
But every time , when call a Course model , I got this error :
exception 'ErrorException' with message 'Trying to get property of non-object' in D:\wamp\www\lms-api\app\Course.php:166
That refers to this line of Course model :
$this->attributes['teacher_name'] = $this->teacher()->first()->full_name;
I do not know how can I solve that and what is problem exactly.
Yikes some interesting answers here.
FYI to those coming after me- getFooAttribute() should return the data, and not modify the internal attributes array.
If you set a new value in the attributes array (that doesnt exist in this model's db schema) and then attempt to save the model, you'll hit a query exception.
It's worth reading up the laravel docs on attribute accessors/mutators for more info.
Furthermore, if you need to access a related object from within the model (like in an accessor) you ought to call $related = $this->getRelation('foo'); - note that if the relation isnt loaded (e.g., if you didnt fetch this object/collection with eager loaded relations) then $this->getRelation() could return null, but crucially if it is loaded, it won't run the same query(ies) to fetch the data again. So couple that with if (!$this->relationLoaded('foo')) { $this->loadRelation('foo'); }. You can then interact with the related object/collection as normal.
$this->attributes['teacher_name'] = $this->teacher()->first()->full_name;
Should be
$this->attributes['teacher_name'] = $this->teacher->full_name;
First thing is that you want to reference the relationship, so loose the brackets (), and because the relationship is belongsTo, you will have one user / teacher returned. So you don't need the first().
We haven't seen your fields but probably you will have to change:
return $this->belongsTo('App\User', 'teacher', 'user_id');
to
return $this->belongsTo('App\User', 'foreign_key', 'other_key');
where foreign_key and other_key are the primary keys that you need to make the join on.
Check this link from the documentation for reference:
https://laravel.com/docs/5.4/eloquent-relationships#one-to-many-inverse
the right way to do this is:
COURSE
public function setTeacherNameAttribute ()
{
$this->attributes['teacher_name'] = $this->teacher->full_name;
}
100% working for me.
I have one to one relationship between Order and Shipment. I have to add the accessor of shipments table column from orders table.
function getOrderNoAttribute()
{
$appendText = "OR100";
if($this->orderShipment()->first()) {
$appendText = $this->orderShipment()->first()->is_shipping === 1 ? "ORE100" : "OR100";
}
return $appendText . $this->attributes['id'];
}
This error is only object data to array use or array data to object data use.
example::
$var->feild insted of $var[feild]
$var[feild] insted of $var->feild
You should use return for accessors . something like this :
public function getTeacherNameAttribute ()
{
return $this->teacher()->first()->full_name ?? '';
}
maybe a course hasn't teacher.

Laravel belongsTo returning null when using 'with'

I'm just getting started with Laravel so please forgive any noobness.
I have a User and Order model, a user has many orders:
# Inside User model
public function orders()
{
$this->hasMany('Order');
}
# Inside Order
public function user()
{
return $this->belongsTo('User');
}
// Not sure if this is upsetting anything (also in Order)
public function products()
{
return $this->belongsToMany('Product');
}
So I think I have the above right.
But when I do this:
$users = User::with('orders')->find(1);
return $users;
I get Call to a member function addEagerConstraints() on null.
However, if I do it the other way around, it works great:
$orders = Order::with('User')->get();
return $orders;
What am I doing wrong / what don't I understand?! Or is my problem bigger than I think?
Database:
The problem is you don't have return for your orders relationship. It should be:
public function orders(){
return $this->hasMany('Order');
}
You should also use your relationships case sensitive. you showed:
$orders = Order::with('User')->get();
is working, but you should rather use
$orders = Order::with('user')->get();
to avoid extra queries to your database in future
For anyone else that runs across this, I was having the same issue, but my problem was that I had the foreign/local keys swapped. Example:
// This is correct for hasX relationships
public function user() {
return $this->hasOne('App\Models\User', 'user_id', 'local_key_user_id');
}
// This is correct for belongsTo relationships
public function user() {
return $this->belongsTo('App\Models\User', 'local_key_user_id', 'user_id');
}
Notice that for hasX relationships, the foreign key is the second parameter, and the local key is the third. However, for belongsTo relationships, these two are swapped.
Probably doesn't answer this particular question but it relates to the title. I had the same issue here is the wrong query
$offer = Offer::with([
'images:name,id,offer_id',
'offer_options:offer_option,value,id,offer_id',
'user:id,name,avatar'])
->select(['id', 'views', 'type', 'status'])
->where('id', $id)->get();
the model look like this
class Offer extends Model {
function user(): BelongsTo {
return $this->belongsTo(User::class);
}
}
The User
class User extends ..... {
function offer(): HasMany {
return $this->hasMany(Offer::class);
}
}
The issue with the query is I was not selecting user_id, i.e in my select function user_id column was not included and that is why I was getting null for user
according to Laravel docs
When using this feature, you should always include the id column and
any relevant foreign key columns in the list of columns you wish to
retrieve.
So the correct query is
$offer = Offer::with([
'images:name,id,offer_id',
'offer_options:offer_option,value,id,offer_id',
'user:id,name,avatar'])
->select(['id', 'views', 'type', 'status','user_id'])
->where('id', $id)->get();

Eloquent model with multiple one to many to same table

I have an existing table structure I'm trying to model with Eloquent (Laravel 4) which has 3 one to many relationships to the same table. Basically, each unit can have a home location, a current location and a customer's location.
Note, I've simplified this for the question. The unit table has an unitid, and a homeid, currentid and customerid. Each of homeid, currentid and customerid is a foreign key in the mysql database to the location table on the locationid. The location table also has a name field.
In my Unit model, I have
public function home() { return $this->belongsTo('Location', 'homeid', 'locationid'); }
public function current() { return $this->belongsTo('Location', 'currentid', 'locationid'); }
public function customer() { return $this->belongsTo('Location', 'customerid', 'locationid'); }
In my Location model I have
public function homes() { return $this->hasMany('Unit', 'homeid', 'locationid'); }
public function currents() { return $this->hasMany('Unit', 'currentid', 'locationid'); }
public function customers() { return $this->hasMany('Unit', 'customerid', 'locationid'); }
Now, in my Units controller I have
$units = Unit::with(['home','current','customer'])->paginate(10);
return View::make('units.index')->with('units',$units);
In units.index view I can refer to
foreach ($units as $unit) {
...
$unit->home->name //<-- this works
$unit->current->name //<-- this doesn't
$unit->customer->name //<-- neither does this
...
}
As fas as I can tell from the documentation, I've done everything right. Why would the first FK work, but neither of the two others?
Edit: the error given on the lines marked as not working (when uncommented) is
"Trying to get property of non-object"
The models are correct, thanks #deczo for pointing out the obvious.
The error was mine - not checking for null on the relations before trying to reference the related records.
I.E. $unit->current->name needed to be is_null($unit->curent)?'':$unit->current->name
A stupid PEBKAC error :-)
--Quog

Categories