Trying to get property of non-object - laravel

I need a little clarification.
This error message "Trying to get property of non-object" to what is referred to when using Eloquent? I'm going crazy. I am using a function:
public function squadra_post()
{
return $this->hasMany('Squadra','id_squadra');
}
that is the model that extends Eloquent Post. When the call:
<?php $squadra = Post::find($roles->id_squadra)->squadra_post; ?>
gives me the error that I mentioned before.
EDIT
his is the class post with their methods. What to give problems is "squadra_post ()" I need to extract the name of the team by id_squadra post content in table.
class Post extends Eloquent implements UserInterface, RemindableInterface
{
protected $table = 'post';
protected $primaryKey = 'id_post';
public $timestamps = false;
public function commenti()
{
return $this->hasMany('Commento','id_post');
}
public function apprezzamenti()
{
return $this->hasMany('Apprezzamenti','id_post');
}
public function squadra_post()
{
return $this->hasMany('Squadra','id_squadra');
}
}
This is the code of the class "squadra"
class Squadra extends Eloquent implements UserInterface, RemindableInterface
{
protected $table = 'squadra';
protected $primaryKey = 'id_squadra';
public $timestamps = false;
}
And finally, this is the code that gives me problems. That is what gives me the error: Trying to get property of non-object
#foreach($post['post'] as $roles)
#if($roles->id_squadra != 0)
$squadra = Post::find($roles->id_squadra)->squadra_post;
#foreach($squadra as $squadra_post)
{{ $squadra->nome }}
#endforeach
#endif
#endforeach

When you tired attempting to find the particular post, it couldn't find it and hence it is throwing an exception saying "Trying to get property of non-object". If it had found the post, it would have returned the squadra_post and it would have been stored in the variable.
But instead it could not find that particular and could not construct an object with it and hence it could not find that particular property name squadra_post. Therefore the error "Trying to get property of non-object".
You could handle this exception by putting the code in a try and catch block.

In the line
$squadra = Post::find($roles->id_squadra)->squadra_post;
the squadra_post() method
returns a collection of objects (posts I guess) and not an object because of the nature of your relationship (1 to many) while Post::find() returns the object. I think this is where the error occurs.
try the following code
$squadra = Post::find($roles->id_squadra);
if ($squadra) {
echo $squadra->name;
foreach ($squadra->squadra_post as $post) {
echo $post->title;
echo $post->content; //etc
}
}
EDIT
Also you'll have to be sure that the foreign key is the id_squadra that you declare in your squadra_post() method.

First off, your relation won't work this way, becuase Laravel 4+ expects relation names to be camelCased and only then you can use dynamic properties.
So rename it to squadraPost()and call like $post->squadraPost, and in case of hasMany you will get a Collection here, no matter if there is any related model or not.
Next thing is checking if related model exists - for this read the answer here: Laravel check if related model exists
And last, but not least: you may get null from find() method, so first make sure this:
$post = Post::find(..)
returns your model, not null. Only then can you call its relation:
if ($post) $post->squadraPost;

Related

Using an Eloquent relationship within an Eloquent accessor?

I am writing a Laravel application that manages training courses.
Each course is represented by a Course model.
A course can have many dates - these are represented by a CourseDate model, with a hasMany relationship between the two:
Each course also has a single "date template", which is a CourseDate, but with an "is_template" boolean set.
I want to create an accessor on the Course model that retrieves its date template.
The (relevant) code for each model is:
class Course extends Model {
public function getDateTemplateAttribute() {
$dates = $this->dates;
$filtered = $dates->where('is_template', true);
$template = $filtered->first();
return $template;
}
public function dates() {
$result = $this->hasMany( CourseDate::class );
return $result;
}
}
class CourseDate extends Model {
public function course() {
return $this->belongsTo( Course::class );
}
}
Then, in my controller, I have this:
// this block works absolutely perfectly
$course = Course::find(1);
$dates = $course->dates;
$working_date_template = $dates->where('is_template', true)->first();
// this one doesn't work at all and says "call to a member function first() on array"
$broken_date_template = $course->date_template;
Stepping through with xdebug in the broken code, the line $dates = $this->dates returns an empty array so everything else afterwards breaks.
Is this a limitation with the Laravel accessor/relationship system? Or am I just being dense and doing something wrong.
I worked this out just now.
I needed to use $this->dates() within the model itself as this returns the relationship and I can then filter it out accordingly using the where() method and other query builder methods.
This was, of course, mentioned in the Laravel documentation - I just didn't spot it.

Laravel - Illegal offset type when accessing property on OneToMany relationship

I'm learning how to use laravel and relationships. I'm having trouble accessing data from a hasMany relationship, I understand this might be a silly question. This might be a duplicate question, but I didn't find any specific answer like this.
I have two models, a salesman table and a prices table table. One salesman has many prices tables, so it's like this:
On Salesman model
<?php
namespace App\Pedidos;
use Illuminate\Database\Eloquent\Model;
class Vendedores extends Model
{
protected $connection = 'Pedidos';
protected $primaryKey = 'CD_VENDEDOR';
public function TabelaDePreco() {
return $this->hasMany('\App\Pedidos\TabelaDePreco', 'CD_VENDEDOR', 'CD_VENDEDOR');
}
}
On the prices table model
<?php
namespace App\Pedidos;
use Illuminate\Database\Eloquent\Model;
class TabelaDePreco extends Model
{
protected $connection = 'Pedidos';
protected $primaryKey = ['CD_VENDEDOR', 'CD_PRODUTO', 'CD_ESTADO'];
public function Vendedores() {
return $this->belongsTo('\App\Pedidos\Vendedores', 'CD_VENDEDOR', 'CD_VENDEDOR');
}
}
On the Controller
public function index()
{
$vendedores = Vendedores::all();
return view('pedidos.tabeladepreco.index')
->with('title', 'Tabela de preços')
->with('vendedores', $vendedores);
}
On the view, this will return TabelaDePreco model
#foreach($vendedores as $vendedor)
#foreach ($vendedor->TabelaDePreco as $tabela)
{{ dd($tabela) }}
#endforeach
Here is a print from the code above:
TabelaDePreco model
As you can see, data is loaded on the $tabela variable.
If I try to print, on the view, {{ $tabela->NR_LIMITE1 }}, I get the illegal offset type error. How do I access this attribute since data is loaded when using dd()? I've tried $tabela['NR_LIMITE1'] but with the same error.
What am I doing wrong?
Best regards.
EDIT:
As pointed by Jonas on the comments, Laravel won't support relationships when one of the tables has composite keys. Back to migrations.
You need to eager load your relation:
$vendedores = Vendedores::with('TabelaDePreco')->all();
return view('pedidos.tabeladepreco.index')
->with('title', 'Tabela de preços')
->with('vendedores', $vendedores);
It may also happen that $vendedor->TabelaDePreco is not defined if there is not TabelaDePreco associated with the $vendedor. Try adding a isset(). Also thing about pagination if you have many entries.

Simple Laravel Relationship

I have two models, one is LeadHistory and the other one is Leads.
Leads:
class Leads extends Model
{
public function lead_history()
{
return $this->hasMany('App\LeadHistory');
}
}
LeadHistory:
class LeadHistory extends Model
{
public function lead()
{
return $this->belongsTo('App\Leads', 'lead_id', 'id');
}
}
When I go into php tinker, get the first Lead ($lead = App\Leads::first();), create a new LeadHistory ($leadHistory = new App\LeadHistory;) and ($leadHistory->message = 'second one';) and ($leadHistory->status_id = 11;) then try to save the leadHistory ($leadHistory->lead()->save($lead);). I get this error message:
BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::save()'
Can someone point me in the right direction, I feel like I have been following the instructions given in Laracasts but can't seem to get the LeadHistory to save with the associated Lead ID.
You’re trying to call save() on a relation rather than a model I think.
Instead, “attach” your LeadHistory model to your Lead model:
$lead = Lead::create($leadAttributes);
$history = new LeadHistory($leadHistoryAttributes);
$lead->history()->attach($history);
You’ll need to rename your relation if you copy-and-paste the above code:
class Lead extends Model
{
public function history()
{
return $this->hasMany(LeadHistory::class);
}
}
I feel the name “lead history” is superfluous when you’re already working with a Lead model.
Try to save $leadHistory first:
$leadHistory->save();
And then:
$lead->lead_history()->save($leadHistory)
Correct me if I'm wrong, but since you already have a model instance of your target App\Leads, I think you should be able to simply access the id of that instance and inject it into a static create call:
$lead = App\Leads::first();
$leadHistory = App\LeadHistory::create([
'message' => 'second one',
'status_id' => 11,
'lead_id' => $lead->id
]);
Before being able to use the create method you'd have to make the properties you want to assign 'mass assignable', by defining a protected property called $fillable in your model:
class LeadHistory extends Model
{
protected $fillable = [
'message',
'status_id',
'lead_id'
];
public function lead()
{
return $this->belongsTo('App\Leads', 'lead_id', 'id');
}
}
This will effectively associate your new record with that lead, since the only thing the Eloquent model does in this regard is providing another way to describe the same relationships your database exercises.
Some other answers mention the attach() method of an Eloquent model. This method is used to attach two models with a many to many relationship (relationships defined with belongsToMany).

Get data from polymorphic relations with namespaces

I have a comments table that have comments of articles, recipes and products. So its a polymorphic relation. I have two columns rel_id and rel_type in my comments table those are being used for this relation.
Now in my Comment.php I have following relation
public function rel()
{
$this->morphTo();
}
And in my other all classes I have following
public function comments()
{
return $this->morphMany('App\Models\Comment', 'rel');
}
When I try to get owner of comment and all its related data I found class not found error. For example
$comments = Comment::find(1);
echo $comments->rel_type //article
Now if I want to get data of article and when I try
$comments->rel
I found article class not found. I am using namespace App\Models\Article I have searched it out I found answer given here. When I try accepted answer, nothing happens, error remains same. When I try second answer of same question, I found
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
My ultimate goal is to get comment owner data like $comments->articles->id and so on. Please guide how can I do that?
I have a blog post about this:
http://andrew.cool/blog/61/Morph-relationships-with-namespaces
There are a couple things you need to do. First, for all of your models that have comments, add the $morphClass variable to the class, e.g.:
class Photo {
protected $morphClass = 'photo';
}
class Album {
protected $morphClass = 'album';
}
Second, on the Comment class, define an array called $rel_types on your Comment class. This will be basically the inverse of what you just did, it's a mapping from short name to full class name.
class Comment {
protected $rel_types = [
'album' => \App\Album::class,
'photo' => \App\Photo::class,
];
}
Finally, define an accessor for the rel_type column. This accessor will first retrieve the column from the database ("album", "photo", etc.) and then convert it to the full class name ("\App\Album", "\App\Photo", etc.)
/**
* #param string $type short name
* #return string full class name
*/
public function getRelTypeAttribute($type)
{
if ($type === null) {
return null;
}
$type = strtolower($type);
return array_get($this->rel_types, $type, $type);
}
Note: $morphClass is something Laravel actually defines, so it has to be named that. $rel_types can be named anything you want, I just based it off of the rel_type column you have.
To make this even better, add that getRelTypeAttribute method to a trait so that any model that morphs can reuse that trait and method.

Laravel 4.1: proper way to retrieve all morphedBy relations?

Just migrated to 4.1 to take advantage of this powerful feature.
everything seems to work correctly when retrieving individual 'morphedByXxxx' relations, however when trying to retrieve all models that a particular tag belongs to -- i get an error or no results.
$tag = Tag::find(45); //Tag model name = 'awesome'
//returns an Illuminate\Database\Eloquent\Collection of zero length
$tag->taggable;
//returns Illuminate\Database\Eloquent\Relations\MorphToMany Builder class
$tag->taggable();
//returns a populated Collection of Video models
$tag->videos()->get();
//returns a populated Collection of Post models
$tag->posts()->get();
My Tag Model class loooks like this:
class Tag extends Eloquent
{
protected $table = 'tags';
public $timestamps = true;
public function taggable()
{
//none of these seem to function as expected,
//both return an instance of MorphToMany
//return $this->morphedByMany('Tag', 'taggable');
return $this->morphToMany('Tag', 'taggable');
//this throws an error about missing argument 1
//return $this->morphToMany();
}
public function posts()
{
return $this->morphedByMany('Post', 'taggable');
}
public function videos()
{
return $this->morphedByMany('Video', 'taggable');
}
}
And the Post and Video models look like this:
class Post extends Eloquent
{
protected $table = 'posts';
public $timestamps = true;
public function tags()
{
return $this->morphToMany('Tag', 'taggable');
}
}
I am able to add/remove Tags to Posts and Videos as well as retrieve the related Posts, and Videos for any Tag -- however -- what is the proper way to retrieve all Models having the Tag name 'awesome'?
Was able to figure it out, would love to hear comments on this implementation.
in Tag.php
public function taggable()
{
return $this->morphToMany('Tag', 'taggable', 'taggables', 'tag_id')->orWhereRaw('taggables.taggable_type IS NOT NULL');
}
in calling code:
$allItemsHavingThisTag = $tag->taggable()
->with('videos')
->with('posts')
->get();
I just used this on Laravel 5.2 (not sure if it is a good strategy though):
Tag model:
public function related()
{
return $this->hasMany(Taggable::class, 'tag_id');
}
Taggable model:
public function model()
{
return $this->belongsTo( $this->taggable_type, 'taggable_id');
}
To retrieve all the inverse relations (all the entities attached to the requested tag):
#foreach ($tag->related as $related)
{{ $related->model }}
#endforeach
... sadly this technique doesn't offer eager load functionalities and feels like a hack. At least it makes it simple to check the related model class and show the desired model attributes without much fear to look for the right attributes on the right model.
I posted a similar question in this other thread as I am looking for relations not known in advance.

Resources