Really sorry to bother you all, but I have a noob question concerning some code in a Laravel 4 Tutorial:
In this tutorial, we have to manage relationships between multiple tables.
Here is the models codes:
<?php
class Auteur extends Eloquent
{
public $timestamps = false;
public function livres()
{
return $this ->hasMany('Livre');
}
}
The other model:
<?php
class Livre extends Eloquent
{
public $timestamps = false;
public function auteur()
{
return $this ->belongsTo('Auteur');
}
}
And when I call :
Route::any('DynEloquent',function()
{
foreach(Livre::with('auteur')->get() as $livre)
echo '"'.$livre->titre.'" a été écrit par '.$livre->auteur->nom.'<br>';
});
I have an ErrorException:Trying to get property of non-object apparently on $livre->auteur->nom.
Any help will be much appreciated since I've already tried to find my way in the official docs and other stuff like the similar questions on eloquent relationship. (even if I'm pretty sure I'm missing an easy thing)(Forgive my English since I'm french.)
Thanks.
Table auteurs:
-id
-nom
-prenom
-naissance
Table livres:
-id
-titre
-auteur_id
It looks like that your relation $livre->auteur is not returning any data, it's probably null, which is not an object and then you get the message Trying to get property of non-object. To be sure you can do:
Route::any('DynEloquent',function()
{
foreach(Livre::with('auteur')->get() as $livre)
{
dd( $livre->auteur );
}
});
You have to check tour relations, if they are really pointed to the correct $tables and your database table, to see if they are correctly filled with proper relational data.
Related
I need to get all appeals, that have appeal_stage.expiration_date less than NOW().
Now I have following solution:
public function scopeExpired($query) {
$query->join('appeal_stage', 'appeals.id', 'appeal_stage.appeal_id')
->where('appeal_stage.expiration_date', '<=', new Expression('NOW()'));
}
but resulted model dump shows that joined table is recognized as pivot table:
So, I want to ask - Is there some more convenient way to perform this request?
My suggestions is use Illuminate\Database\Eloquent\Relations\Pivot somehow, bu I do not quiet understand, how Pivot can be used here.
UPD 1
Models has next relations:
public function stages()
{
return $this->belongsToMany(Stage::class)->withPivot('prolongated_count', 'expiration_date')->withTimestamps();
}
public function appeals() {
return $this->belongsToMany(Appeal::class);
}
You should be able to do something like this:
$appeal->stages()->wherePivot('expiration_date', '<', $now)->get()
You should create relationship in appeal model
public function stages()
{
return $this->belongsToMany(Stage::class,'appeal_stage','appeal_id','stage_id')->wherePivot('expiration_date','<',Carbon::now())->withTimestamps();
}
In belongs To Many relationship second argument is your Pivot table name
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.
I have two tables: client and payment_term. I want to save the client table while keeping a relationship with payment term.
My model classes are:
class Client extends Model {
public function payment_term() {
return $this->hasOne('App\Model\PaymentTerm');
}
}
class PaymentTerm extends Model {
public function client() {
return $this->hasOne('App\Model\client');
}
}
I need to insert client with payment.my code is given below but not working,
$client = new Client();
$client->name = Input::get('name');
$client->save();
//Payment term
$term = PaymentTerm::findOrFail(Input::get('term_id'));
$client->payment_term()->save($term);
}
Could you help me to solve the issue? I have gone through docs and some others questions, but none of them are working for me. I also want to know the best practice for inserting a related model.
Your relationships are not setup correctly. The complement to a hasOne relationship is a belongsTo relationship. Additionally, it is the model that contains the foreign key field that is on the belongsTo side.
From the code, it looks to me like you have it setup so that the client table has a term_id field (the foreign key to the payment_term record). If this is the case, your relationships should be:
class Client extends Model {
public function payment_term() {
return $this->belongsTo('App\Model\PaymentTerm', 'term_id');
}
}
class PaymentTerm extends Model {
public function client() {
return $this->hasOne('App\Model\Client', 'term_id');
}
}
You can find more on Laravel relationships in the documentation here.
Im not sure but I think your $client->save() is causing the issue.
Try using this code instead -
$client = new Client();
$client->name = Input::get('name');
//Payment term
$term = PaymentTerm::findOrFail(Input::get('term_id'));
$term->client()->save($client);
Also you might need to change App\Model\client to App\Model\Client
About best practices I think the code examples on documentation could help you out - http://laravel.com/docs/5.0/eloquent#inserting-related-models
I have a table called champ_sales which contains champions that belong to table champions. I've set up my models properly, and I'm trying to query in the exact same way the documentation here: http://laravel.com/docs/eloquent#querying-relations states, but it's not working.
class ChampSales extends Eloquent {
protected $table = 'champ_sales';
public function champ(){
return $this->belongsTo('Champion');
}
}
class Champion extends Eloquent {
protected $table = 'champions';
public function skins(){
return $this->hasMany('Skin');
}
//relevent relation here:
public function championOnSale(){
return $this->hasMany('ChampSales');
}
public function skinOnSale(){
return $this->hasMany('SkinSales');
}
}
My query: Find start_date in table champions for id=2
$champsales = ChampSales::find(2);
echo $champsales->champ->start_date;
Running this gives me a vague error that says "Trying to get property of non-object". I'm not really sure what I've done wrong, followed the documentation to the dot.
I just fixed it. I defined the local key and foreign key in champ(). I thought the laravel naming convention would pick that up fine, but I guess not.
class ChampSales extends Eloquent {
protected $table = 'champ_sales';
public function champ(){
return $this->belongsTo('Champion', 'champion_id', 'id');
}
}
I'm having some trouble while saving a polymorphic one-to-one relation with Laravel 4, this is my model:
namespace App\Models\Proveedores;
class Proveedor extends \Eloquent {
public function proveedorable () {
return $this->morphTo('proveedorable', 'proveedorable_type', 'proveedorable_id');
}
And this is the specific model:
namespace App\Models\Proveedores;
class ProveedorTerminacion extends \Eloquent {
public function proveedor () {
return $this->morphOne ('App\Models\Proveedores\Proveedor', 'proveedorable', 'proveedorable_type', 'proveedorable_id');
}
This way I'm trying to save a Proveedor associated with a specific ProveedorTerminacion model, but for some reason a row for ProveedorTerminacion is created in my table, but not for Proveedor and Laravel won't show any error and return an empty response, what's wrong?
$terminador = ProveedorTerminacion::create (Input::all());
$proveedor = new Proveedor;
$proveedor->fill (Input::all());
$proveedor->proveedorable()->associate ($terminador);
$proveedor->save ();
Associate method doesn't work correctly with morphTo, as it is never setting morphable_type, so don't use it. I'm pretty sure your code should throw fatal error because of that by the way. It requires bugfix.
Instead invert creating the relation and do it in the context of morphable object:
$terminador = ProveedorTerminacion::create (Input::all());
$proveedor = new Proveedor;
$proveedor->fill (Input::all());
$terminador->proveedor()->save($proveedor);
I'm fixing that and going to send a PR to the laravel repo after some testing. I'll update my answer when it's done.
Here it is: https://github.com/laravel/framework/pull/4249