Laravel Method [hasMany] does not exist - laravel

I have 2 controllers and models:
User Controller & Model
Hero Controller & Model
Each user can have unlimited heroes - it means that the relationship between them is one to many.
In my UserController I created the following method:
/**
* Get the heroes of the user.
*/
public function heroes()
{
return $this->hasMany(Hero::Class);
}
while in my HeroController I created this method:
/**
* Get the user that owns the hero.
*/
public function user()
{
return $this->belongsTo(User::class)
}
Added this to my routes file:
Route::get('userHeroes', 'UserController#heroes');
and it returns this error:
{"error":{"message":"Method [hasMany] does not exist.","status_code":500}}
What could have gone wrong.. ?

The controller is just a delegate between the request and the return data - you tell it that you want something, it figures out what you want, and then it calls the appropriate places to get something to return.
The hasMany() and belongsTo() methods, on the other hand, are logic specifically related to the Hero and User models, on the other hand.
What you need is to move the heroes() method to your User model, because a user can have many heroes. Also need the user() method to your Hero model, because a hero belongs to a user.
Then you put an action call in a controller. Let's say, for instance, that you have a UserController which has an getHeroes() method. That might look like this:
public function getHeroes() {
$user = auth()->user();
$heroes = $user->heroes;
return $heroes;
}
And that will format it to JSON. Just an example.
But you might want to read a tutorial or two about this, since it's fairly basic stuff and it's good to get a good handle on early on. Please don't take that the wrong way - we're happy to help if you run into problems, I just think you might need a stronger foundation. The screencasts at Laracasts are highly recommended for this purpose.

it must be declared in models, not in controllers, hasMany() is a method in eloquent models.

hasMany and belongsTo methods are eloquent class methods.
And we inherit eloquent in our model so that we can use the eloquent methods functionality.
In order to use the relation, you have to define the relation method in respective model class and then you can call from controller.
Please refer the documentation Eloquent relationship documentation
Hope i have cleared your doubt.
Thanks

Related

Repleace relationship by name of this relationship

I have a model User with fileds like - colorhair_id, nationality_id, etc. Of course I have a relationship to other model. Problem is that I want to return nationality from User i must do that:
User::find(1)->colorhair->name
In next time I need to use
User::find(1)->nationality->name
It works but it's not look professional and it's dirty. How can I change query or something else to return object with repleace field like nationality_id to nationality with name of that. Any idea?
You can use Laravel Mutators. Put below two functions into the User model
public function getHairColorNameAttribute(){
return $this->colorhair->name
}
public function getNationalityNameAttribute(){
return $this->nationality->name
}
Then when you simply access it.
User::find(1)->hair_color_name;
The next time
User::find(1)->nationality_name;
If you want to get these values by default use $append in the model. Put the following line to the top of the User model
protected $appends = ['hair_color_name','nationality_name'];
Note: In laravel 9 mutators little bit different from the above method.
Bonus Point :
if you access values in the same scopes don't use find() method in each statement.
$user = User::find(1);
then
$user->hair_color_name;
$user->nationality_name;

How do I use a Laravel dynamic relationship?

I am a newbe in Laravel. The docs show how to use relationships like this:
One To Many (Inverse) / Belongs To
Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany relationship, define a relationship method on the child model which calls the belongsTo method:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo(Post::class);
}
}
Once the relationship has been defined, we can retrieve a comment's parent post by accessing the post "dynamic relationship property":
use App\Models\Comment;
$comment = Comment::find(1);
return $comment->post->title;
My question is: Where is this code? In a controller or in a view?
If you use MVC structure, you should understand that
Model is layer where you store your data
View is layer where you should only display your data
and Controller is layer where you can keep your logic.
If you have a lot of difficult logic or big application, you should better to use Services, as layer between Controllers And Models.
Receiving Comments from model and prepeare them should be in controller level. In view level you just define how to show them to user.
I hope it will help you to understand difference between logic layers.
you can access this relationship in controller or view like this-
suppose you want to make relation between product model and brand model:-
in product model:-
public function brand(){
return $this->belongsTo('App\Model\Brand','brand_id','id');
}
now you are able to see which product belongs to which brand without any query or using loop.
just do in controller:-
$product=Product::with('brand')->get();
here you get all the data...
and when you use it on **view **just do it:
{{$product->brand->brand_name}}
//brand name should the column name
I hope you understood...
Happy Learning!

Laravel - why is a Model's relations not being loaded?

I have a Laravel 5.3 site and I think maybe I have some weird things going on due to some actions happening in API controllers and some happening in the regular controllers.
Or maybe an issue where at some times I am dealing with a Model, and sometimes with an Eloquent Collection.
The issue is, I am trying to retrieve relations on a Model and am getting null.
For instance, I have course Model that relates to week Model.
In course Model I get week items as
public function weeks()
{
return $this->hasMany(Week::class, 'course_id');
}
In backend, these relations get sent in this way:
$course->load('weeks')
All is good.
But when course item gets deleted and I try and take action in the week controller as
static::deleting(function($course) {
$course->weeks->delete();
});
$course->weeks is null. At that time I see in the database that all is good and this course items does indeed have a week item related, but $course shows 0 relations.
So something odd is happening where $course->webinars is not grabbing the week items related.
Is there something that I am fundamentally doing wrong? Maybe it is because in the models I have these sorts of statements:
protected $table = 'Week';
Are these preventing the relations from being pulled? I always thought that is I had some function in a model that returns relations that those relations would always be available when I use syntax $course->weeks.
Ideas?
Thanks again,
You can simply setup migrations to automatically delete from weeks if you delete a course, provided you have foreign key relationship.
If you have a column course_id in weeks table then add this into your migration
$table->foreign('course_id')
->references('id')->on('courses')
->onDelete('cascade')
I think you can use Observers. In your AppServiceProvider, first register the observer.
public function boot()
{
Course::observe(CourseObserver::class);
}
Now, add an Observer class.
class CourseObserver
{
public function deleting(Course $course)
{
$course->weeks()->delete();
}
}

Laravel Eloquent relationship efficency

When I declare a relationship in a model, for example:
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
}
Are comments retrieved from the database the moment I retrieve the Post instance or the moment I write
$post->comments;
?
The answers so far solve this problem in pieces, but not very clearly so allow me to help. To answer your question bluntly, creating a Post instance does not also load associated comments.
Here is why:
When you define an Eloquent relationship, you are basically attaching a whole new 'query' method to your object and so it won't actually be executed unless you call it.
As a simple example we have Car:
class Car {
public $color;
public function __construct() {
$this->color = 'blue';
}
public function makeRed() {
$this->color = 'red';
return $this;
}
}
In this example, the instantiated Car will only have one property, color. This car will be blue unless you call the makeRed() method and change it. It does not compute both options simultaneously expecting that you may decide to change it's color.
So to relate that back to the Eloquent relationship, the comments method returns a relationship object, but only if the method is called on the Post object. Up until that point, your Post object will not automatically call it's own methods. Basically, don't worry about an object becoming large with a ton of methods as these methods only contribute to object size significantly if they are actually called.
If you wish for comments to be loaded with your Post immediately, eager loading the initial query will allow this by:
$post = Post::with('comments')->findOrFail('post_id');
Otherwise, the following would give you the comments for a given post:
$post = Post::findOrFail('post_id');
$post->comments;
Please see the Laravel documentation on Eager Loading for more information.
Hope this helps!
The answer its simple:
$post->comments() returns the relationship object
$post->comments returns the result of the relationship
So the moment you do $post->comments that means fetch relationship and execute query, therfore returns relational database results.
They are retrieved when you ask for it, i.e $post->comments. If you want to eager load them, you can write Post::with('comments')->get(). Check out documentation. It explains eager loading and the N+1 problem.
From the docs:
When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem.

Relationship mapping with NeoEloquent

I'm tinkering with Neo4j 2.3.0 and Laravel 5.1 using NeoEloquent. I've set up a couple of dummy nodes and some relationships between them:
image of Neo4j model - apologies, I cannot insert images directly yet :)
So articles can use a template. The inverse of this relationship is that a template is used by an article.
I've set up the classes like so:
Class Template extends Model
{
public function articles()
{
return $this->hasMany('App\Article', 'USED_BY');
}
}
And:
Class Article extends Model
{
public function template()
{
return $this->belongsTo('App\Template', 'USES');
}
}
So far, so good, I think.
I have a page where I am wanting to eventually list all of the articles in the system, along with some useful metadata, like the template each ones uses. For this, I have set something up in the controller:
$articles = array();
foreach (Article::with('template')->get() as $article) {
array_push($articles, $article);
}
return $articles;
Not the most elegant, but it should return the data for both the article and it's associated template. However:
[{"content":"Some test content","title":"Test Article","id":28,"template":null},{"content":"Some flibble content","title":"Flibble","id":31,"template":null}]
So the question is - why is this returning null?
More interestingly, if I set up the relationship to the same thing in BOTH directions, it returns the values. i.e. if I change the USED_BY to USES, then the data is returned, but this doesn't make sense from an architectural point of view - a template does not 'use' an article.
So what am I missing?
More interestingly, if I set up the relationship to the same thing in BOTH directions, it returns the values.
That's correct, because this is how it operates. It is worth knowing that the relationship methods you have defined represent the relationship itself, which means for both models Template and Article to target the USED_BY relationship from any side it has to be the same in articles() and template.
The solution would be to use something like USES (or any notion you like) on both sides. This reference should help you make good decisions regarding your relationships.
On the other hand, if you still wish to have different relations on the sides then kindly note that in your model (image) both relationships are in outgoing direction. i.e. Fibble-[:USES]->Template and Template-[:USED_BY]->Fibble which means template() should be an outgoing relationship such as hasOne instead of belongsTo which is incoming.

Resources