Trying to get data via related table in Laravel - php

What I'm trying to do is to show the posts that have been saved by the user in the profile. I will try to explain it as good as possible refering to my code. So:
public function userProfil($id)
I have the profile function which get the data from userprofile table. and inside I have the following code for saved data:
$authed = User::find($id);
$savedarticles = $authed->mysaves;
$allsavings = DB::select("Select * from article where id=$savedarticles->id");
But this code does not work like this anyway. I can do this instead:
$authed = User::find($id);
$savedarticles = $authed->mysaves;
But when I try to get articles from article table with the article_id of mysaves, it does not work such as this:
$allsaved= DB::table('article')->where('id', $savedarticles->article_id);
the error it gives is like:
Property [article_id] does not exist on this collection instance.
although savearticle table has article_id I can output it without the line above and in view I get them as:
#foreach($savedarticles as $savedarticle)
<p>{{$savedarticle}}</p>
#endforeach
it gives me everything that is in the savearticle table and I can get do savedarticle->article_id and get article_id but can't get it in controller.
I am using Laravel 5.4.

The error message Property [article_id] does not exist on this collection instance. means you are trying to get an attribute of a single instance but from a collection.
For example the collection could be like
[$article1, $article2, $article3]
therefore what you tried to do is something similar to
[$article1, $article2, $article3]->article_id
You are trying to get an attribute from a collection instead of a single instance.
As for your query, you can use where in sql statement to search for rows that match any item in an array
$allsaved= DB::table('article')->whereIn('id', $savedarticles->pluck('article_id')->all());

What I have understood is that A USER has many POSTS and a POST belong to an article.
If this is true then you have to do following.
1: In USER model define a relation to get all posts. like below.
public function posts() {
// Foreign key will be a key that is stored in posts table and represent the user MAY BE: user_id
$this->hasMany(Posts::class, 'foreign_key', 'local_key')
}
This will allow you to get all posts belong to a user.
2: In posts, model defines a user relation like below.
public function user() {
$this->belongsTo(User::class, 'foreign_key', 'local_key');
}
This will allow you to get a post User;
3: Now in your controller you will have something like this.
public function show($user_id) {
// find a user with posts as eager loading(to avoid query again)
$user = User::with(['posts'])->where('id', $user_id)->first();
// get all posts that belong to this user
$posts = $user->posts;
}
In controller show($user_id) method you will have a user data as well as user posts data. Now if you want to get a post relations then simply define as below. let say a post belongs to an article as well.
4: In posts, model defines a relation to get an article.
public function article() {
// This will allow you to get a post artcle
$this->belongsTo(Article::class, 'foreign_key', 'local_key');
}
Now you can get the article as well while finding a user. please see below. I am rewriting controller show action to give you a better understanding.
5: Get a user with user_id
public function show($user_id) {
// find a user with posts as eager loading(to avoid query again)
// eager loading for posts & post child, this will give you NOSQL at runtime and all data will come from one query.
$user = User::with(['posts', 'posts.article'])->where('id', $user_id)->first();
// get all posts that belong to this user
$posts = $user->posts;
foreach($posts as $post) {
$article = $post->article; // Child relation of post.
}
}
Hope you will understand the flow, you have to make sure models relation to work it perfectly. If you need further help please let me know.

Related

Get name instead of ID one to one relationship

I have a make table and post table. Make table saves make names as make_code and make_name.
Post table has a column make. While saving a post, it will save make in make_code.
While displaying in blade, I want it to display as make_name. How can I do it?
Currently {{$post->make}} gives me make_code. I need it to show make_name.
I think its a one-to-one relationship that's needed. I tried putting it in model but did not work. How can I achieve it?
MAKE MODEL
class Make extends Model
{
public function make()
{
return $this->belongsTo(App\Post::class);
}
}
POST MODEL:
class Post extends Model
{
protected $table = 'posts';
}
Update
As Tim Lewis noticed:
the relationships can't be named make, as that's a conflict.
Assuming that the your relationship work like this:
a Make has many Post
a Post belongs to a Make object.
| Note: Correct me if I'm wrong.
So, if this is correct, you should define your relationships like this:
Post.php
public function make_rel()
{
return $this->belongsTo(Make::class, 'make', 'make_code');
}
Make.php
public function posts()
{
return $this->hasMany(Post::class, 'make', 'make_code');
}
Check the One-to-Many and One-to-Many (Inverse) relationship sections of the documentation.
So, you could do in your controller (or wherever you want):
$post = Post::find(1);
dd($post->make_rel->make_name); // 'Harley Davidson'
Additionally, you could create a computed property as a shorcout to access this related property in your Post model:
Post.php
// ...
public function getMakeNameAttribute()
{
return $this->make_rel->make_name;
}
Now, you can access it like this:
$post = Post::find(1);
dd($post->make_name); // 'Harley Davidson'
Suggestion
As a suggestion, I strongly advice you to change your foreign key column from make to make_id (in your 'posts' table) to avoid conflicts. Also, you could relate the post to the make primmary key instead of a custom key given the fact that this link is almost invisible and it is handled by Laravel. This would speed up the execution of the query because primmary id's are indexed by default.

Calling Laravel relationship with aggregate

If I have a Laravel 5.5 model called User that hasMany Posts and each Post hasMany Hits, is there an aggregate function I can call to get the total number of Hits for a User across all Posts, where the Hit was created in the last week?
It seems like there may be a clever way to do it besides doing something like
$hits = $user->posts()->hits()
and then looping over those hits to check created date.
In this case it seems like raw sql would be better, but I figured there may be an Eloquent way to handle a situation like this.
I think the right solution is just to use a HasManyThrough relationship to grab all the Hit rows, joined through the posts table.
So it'd look like this on the User model (roughly):
return $this->hasManyThrough(
Hit::class,
Post::class
// if you have non-standard key names you can specify them here-- see docs
);
Then when you have your User model you can just call $user->hits to get a collection of all the associated hits through all the user's Posts
You can add the code below to your Post model.
protected static function boot()
{
parent::boot();
static::addGlobalScope('hitCount', function ($builder) {
$builder->withCount('hits');
});
}
It automatically provides a field hits_count whenever you fetch a post.
$post = Post::first();
$hits = $post->hits_count; //Count hits that belongs to this post
You can read the documentation here to customize it to your need.
Set HasManyThrough relation in the User model:
public function hits()
{
return $this->hasManyThrough('App\Models\Hits','App\Models\Posts','user_id','post_id','id');
}
then you can do this:
$reults = $user->hits()->where('hits_table_name.created_at', '>=', Carbon::today()->subWeek())->count();
HasManyThrough Link
Use DB::enableQueryLog(); and DB::getQueryLog(); to see if executed SQL Query is correct;

How to access related record in CakePHP with mysql?

I have a database of two tables. One with blog posts and one with users, related by a user_id field in the post table. On my index page I have a table of the posts and I want to add the author to that however I want to display the user's name rather than their ID. I am trying to add an author field to my post objects like this in PostsController:
public function index() {
$this->set('posts', $this->Post->find('all'));
foreach ($this as $post){
$post['Post']['author'] = $this->User->findById($post['Post']['user_id']);
}
}
however this brings the error that I am calling findById on null. I am very new to php so I think my understanding of how to use the loop may be incorrect. Perhaps there is a better way which does not require the loop?
Controllers in CakePHP, by default, only load their own models. If you need an additional model at some point, you need to load it in manually.
That won't solve your problem though, because you're setting the result for the find() action straight into the view. You'll want to wait with that until you add the users to it. Oh, and you usually can't iterate through $this with foreach, unless your class implements an Iterator-like interface (which controllers should never have a reason to do)
public function index() {
// first load in the User model
$this->loadModel('User');
// store the posts in a local variable first
$posts = $this->Post->find('all');
// loop through the local variable, also keep the index so we can reference
// the post we're modifying
foreach ($posts as $index => $post) {
$post['Post']['author'] = $this->User->findById($post['Post']['user_id']);
// write the modified $post back into the $posts array
$posts[$index] = $post;
}
// **now** you can make $posts available to your view
$this->set('posts', $posts);
}
Once you have this sorted out, read up on linking models together. There's a way to set up your Post model so that it will automatically fill $post['Post']['author'] with the corresponding User, without you having to do that manually.
Better you specify the relation in model.
In Post Model initialize the relation between post and user
public $hasOne = 'User';
Now in controller use Contain() to get linked models data
$posts = $this->Post->find('all')->contain(['User']);
$this->set('posts', $posts);
You will get User object with each post record which you can use to get user name, you do not need to write a separate query to fetch the user name.

Eloquent: Has Many Through Relationships

I am trying to figure out a relationship but I can't seem to solve the issue.
So what my script does first is checking if there is a valid session where status = 0.
Then I want to check if there is a valid trial where status = 0 ->first() associated with that session. And if so, I want to grab all the relevant data related by trial_id.
I understand what logic is required. However, I am wondering if there is a method to do this with as little commands as possible using Eloquent relationships.
Specifically, once i have the $session object. How can I filter the trials, in order to get the appropriate stimuli_tracker data?
The important components to the relationships for the table is as follows:
Sessions
id (has one to many relationship to trials(sessions_id)
user_id (foreign key)
status
Trials
id (one to many relationship with stimuli_tracker)
sessions_id (foreign key)
status
Stimuli_Tracker
trials_id (foreign key)
stimulus
stimulus_type
Sessions Model
class Sessions extends Model
{
protected $table = 'sessions';
public function stimuliTracker()
{
return $this->hasManyThrough('App\StimuliTracker', 'App\Trials', 'sessions_id','trials_id');
}
}
Trials Model:
class Trials extends Model
{
public function stimuli()
{
return $this->hasMany(App\StimuliTracker);
}
}
EDIT
I have tried in artisan tinker to
$object = \App\Session::where(arg);
then I tried to
$object->stimulus
but didn't work. I tried a few other fields but I only received null. Maybe I'm not getting how to grab the content properly
$object->stimulus is an undefined attribute based on what you've shown in your code.
To access the stimulus information for your session, you have to use the name of the relationship, which in this case is:
$object->stimuliTracker
The thing is that this will return an Eloquent Collection because it is a hasManyThrough relationship (which is a hasMany of a hasMany).
I'm assuming that the 'stimulus' attribute belongs to the StimuliTracker class. If this is the case, then you will need to loop through your StimuliTracker Collection to extract it:
foreach ( $object->stimuliTracker as $record )
{
$stimulus = $record->stimulus;
// do something with $stimulus
}
EDIT (Added):
If you are just looking for an array of the values in the 'stimulus' attribute, you can get that with the lists() method:
$stimulus_values = $object->stimuliTracker->lists('stimulus');

Eloquent where owner equals follow

I am trying to make a twitter like feed in an application, I have a database called connections where inside there's user and follow and another database called feed containing owner which would equal to the follow column in connections.
What I could do if had every id of a follower statically is to use where('owner', '=' $follow) on each follower and return it.
I tried this approach but it wasn't ideal:
Get each follower inside connections;
foreach(follower) {
Get 10 of the latest posts orderBy "created_at";
Push into array;
}
shuffle array;
limit array to 15;
return array;
That also ended with the returned array not being ordered by created date.
How would I use eloquent to get the feed item only if the user follows the owner in the best/simplest way?
Are there any specific Laravel tools that can be used?
Also the database layout isn't fixed as it is, it can be altered if needed to better suite this.
You need to create a many-to-many relationship between the user and itself. See the laravel eloquent documentation http://laravel.com/docs/eloquent#relationships. I didn't test this code but it should be enough to get you started down the right track.
Create a pivot table called "user_following" with:
(int) id, (int) user_id, (int) following_id
Then do something like this:
<?php
// Model
class User extends Eloquent {
public function following()
{
return $this->belongsToMany('User', 'user_following', 'user_id', 'following_id');
}
public function tweets()
{
return $this->hasMany('Tweet')->orderBy('created_at', 'desc');
}
}
// controller
$tweetsOfWhoImFollowing = User::find($id)->following->tweets;

Categories