How To Get Article's Users and Comments With Eloquent - php

There are three database tables users, articles and a joining table article_users_comments, which holds the comment, the user id commented the article and the commented article id.
I can achieve the following thing with pure SQL join, but I want to do it with Eloquent, I thought that it would be quite easy, but I am kind of confused right now.
I have been trying different things, but it still doesn't work.
// User
class User extends Authenticatable implements MustVerifyEmail,CanResetPassword{
public function comments()
{
return $this->hasMany('App\ArticleComments');
}
}
// Article
class Article extends Model{
public function getArticles(){
$articles = Article::paginate(3);
return $articles;
}
public function getSingleArticle($title){
$article = Article::where('title','=',$title)->get();
return $article;
}
public function articleComments()
{
return $this->hasMany('App\ArticleComments');
}
}
// ArticleComments
class ArticleComments extends Model{
protected $table = 'article_users_comments';
public $timestamps = false;
public function article()
{
return $this->belongsTo('App\Article');
}
public function user()
{
$this->belongsTo('App\User');
}
}
// ArticleController(showing only the show method), which passes the data to the certain view
instantiating the Article Model
class ArticleController extends Controller{
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($title)
{
$removeDashesFromUrl = str_replace('-',' ',$title);
$am = new Article();
$data = $am->getSingleArticle($removeDashesFromUrl);
return view('article',['article'=>$data]);
}
}
I want to get the comments and the users(which have commented the article) for a certain certain article.

You should set the foreign key in your articleComments and article relations:
Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with _id. However, you may pass a custom key name as the second argument to the belongsTo method:
Article Model
public function articleComments()
{
return $this->hasMany('App\ArticleComments','commented_article_id');
}
ArticleComments Model
public function article()
{
return $this->belongsTo('App\Article','commented_article_id');
}
You can get the comments from a article using the relation:
$article = Article::find($id);
$article->articleComments; // This will return all comments for the given article
You could use a foreach loop and access each attribute from each comment:
foreach($article->articleComments as $comment)
{
echo $comment->id;
echo $comment->user->id;
echo $comment->user->username;
.
.
.
}
You can access the user and any of his attributes just calling the relation in your comment like i did above.
For more info: click here.
Note: i strongly recommend you changing your model name to Comment, we don't use model names in the plural, always in singular.

Related

Slug problems show with laravel

I have model:
class Header extends Model
{
use HasFactory;
public function getRouteKeyName()
{
return 'slug';
}
}
my controller:
public function show($id)
{
$headers = DB::table('headers')->find($id);
$blocks = DB::table('blocks')->where('header_id', $id)->get();
return view('test', compact('headers', 'blocks'));
}
my route:
Route::get('/{id}', [MainController::class, 'show'])->name('show');
but I can't show slug, I see localhost:8000/id
error: Attempt to read property "id" on null
You are using getRouteKeyName which is useful for Route-Key binding. But your route is not set up that way.
It also does not help you with the find() method in the Model.
Also, you are not using your model in your DB call. Any methods or properties defined in your model will therefore not be used.
And you should set up relationships to get related data.
Respecting your current route, you should do something like this:
class Header extends Model
{
use HasFactory;
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'slug';
// ^-- this is what you use to tell Model what column to use for find()
// only use this if you do route-model binding
public function getRouteKeyName()
{
return 'slug';
}
// relationship to find all blocks that belong to this header_id
public function blocks()
{
return $this->hasMany(\App\Model\Blocks::class);
}
}
Then for the DB Call:
public function show($id)
{
$header = Headers::find($id);
$blocks = $header->blocks ?? [];
return view('test', compact('header', 'blocks'));
}

Laravel Eloquent: Inverse of Many To Many (Polymorphic)

Example copied from official Laravel Docs:
For example, a Post model and Video model could share a polymorphic relation to a Tag model. Using a many-to-many polymorphic relation in this situation would allow your application to have a single table of unique tags that may be associated with posts or videos. First, let's examine the table structure required to build this relationship:
posts
id - integer
name - string
videos
id - integer
name - string
tags
id - integer
name - string
taggables
tag_id - integer
taggable_id - integer
taggable_type - string
From a tag object I wanted to get all the videos and posts, to which that subjected tag belongs (in case of morphOne an morphMany I can do that by morphTo() method)
Laravel says, I need to define both the videos and posts methods in Tag model in order to define an inverse but I want a relation like taggables which will return the respected parent (whether it's Post or Video)
Reference
I need a similar thing like imageable (but it is polymorphic one to one and I need this kind of thing in many to many)
You can just use MorphOne/MorphMany in your pivot model.
https://laravel.com/docs/8.x/eloquent-relationships#defining-custom-intermediate-table-models
class Video extends Model
{
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable')->using(Taggable::class);
}
public function taggables()
{
return $this->morphMany(Taggable::class, 'taggable');
}
}
class Post extends Model
{
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable')->using(Taggable::class);
}
public function taggables()
{
return $this->morphMany(Taggable::class, 'taggable');
}
}
class Tag extends Model
{
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable')->using(Taggable::class);
}
public function videos()
{
return $this->morphedByMany(Video::class, 'taggable')->using(Taggable::class);
}
public function taggables()
{
return $this->hasMany(Taggable::class/*, 'tag_id'*/)
}
}
use Illuminate\Database\Eloquent\Relations\MorphPivot;
class Taggable extends MorphPivot
{
public $incrementing = false; // this is the default value. Change if you need to.
public $guarded = []; // this is the default value. Change if you need to.
protected $table = 'taggables';
public function taggable()
{
return $this->morphTo();
}
public function tag()
{
return $this->belongsTo(Tag::class/*, 'tag_id'*/);
}
}

Rretrieving data from foreign key, One to One Relationship. Laravel

I am trying to retrieve value from foreign key table with one to one relation. I have defined two models:
1. Blog
class Blog extends Model
{
//
protected $table = 'blogs';
public function blog_category()
{
return $this->hasOne('App\Blog_Category');
}
}
2. Blog Category
class Blog_Category extends Model
{
//
protected $table=('blogs_categories');
public function blog()
{
return $this->belongsTo('App\Blog');
}
}
I have got blogs_categoryid in blogs table that has been referenced to id from blogs_categories table.
I have tried following:
{{$blog->blogs_categoryid->category}}
But it is showing "trying to get property of non-object". What is going wrong here? Can anyone help me?
Blog model content should be:
class Blog extends Model
{
protected $table = 'blogs';
public function blog_category()
{
return $this->hasOne('App\Blog_Category', 'blogs_categoryid');
}
}
Then use with when you want it to query relation table:
$blog = Blog::with('blog_category')->get();
$categoryObject = $blog->blog_category;
$categoryId = $categoryObject->id;

Laravel querying model relations

I'm still struggeling with the laravel Models. At first I tried doing it all using the tables, but thats not smart, I'll miss out on lots of the laravel functions.
I have the following setup
ProjectTwitterStatus links the projects and the twitter statuses.
TwitterStatus has all the details of a twitter status and has a unique ID ('posted at' datetime of tweet is among the details)
TwitterRetweets has the ID of the TwitterStatus - the actual retweet - and the tweet ID of the retweeted status
TwitterReplies has the ID of the TwitterStatus - that is the actual reply - and/or the user ID if not a reply to a status but to a user.
What I want? To get for each date (DATE(datetime)) the count of the statuses, retweets and replies, using the laravel model relations.
These are the models.
class ProjectTwitterStatus extends Eloquent {
protected $table = 'project_twitter_statuses';
protected $softDelete = true;
public function twitterStatus() {
return $this->belongsTo('TwitterStatus');
}
public function project() {
return $this->belongsTo('Project');
}
}
class TwitterStatus extends Eloquent {
protected $table = 'twitter_statuses';
public function twitterRetweet() {
return $this->hasMany('TwitterRetweet');
}
public function twitterReply() {
return $this->hasMany('TwitterReply');
}
public function twitterUser() {
return $this->belongsTo('TwitterUser');
}
public function projectTwitterStatus() {
return $this->hasMany('ProjectTwitterStatus');
}
}
class TwitterRetweet extends Eloquent {
protected $table = 'twitter_retweets';
public function twitterStatus() {
return $this->belongsTo('TwitterStatus');
}
}
class TwitterReply extends Eloquent {
protected $table = 'twitter_replies';
public function twitterStatus() {
return $this->belongsTo('TwitterStatus');
}
}
I got the count of the twitterStatuses using this:
$twitterStatuses = TwitterStatus::has('projectTwitterStatus')
->groupBy(DB::raw('DATE(datetime)'))
->get(array(DB::raw('COUNT(id) AS tweets'),DB::raw('DATE(datetime) AS date')));
I tried for example this to get the retweet count added but that has no effect (a reference to the model apears in the object -> array().
$twitterStatuses = TwitterStatus::has('projectTwitterStatus')
->with(array('twitterRetweet' => function($query)
{
$query->count();
}))
->groupBy(DB::raw('DATE(datetime)'))
->take(10)
->get(array(DB::raw('COUNT(id) AS tweets'),DB::raw('DATE(datetime) AS date')));
Can anyone point me in the right direction?
Not 100% sure how your intended solution is to be used - Assuming you simply want a count of the number of retweets related to twitterStatus?
$count = $twitterStatus->twitterRetweet()->count();
where $twitterStatus is an already retrieved model - not a collection.
if $twitterStatus is a collection to iterate through you can also eager load the related model using either with() or load()
Then you can iterate through each model in the collection - depends on how you wanted to use the results

Laravel 4, how to access reverse one-to-many relation?

Code:
<?php
class Catering extends \Eloquent {
protected $table = 'catering';
public $timestamps = FALSE;
public function offers() {
return $this->hasMany('Offer', 'cid');
}
}
class Offer extends \Eloquent {
protected $table = 'catering_offer';
public $timestamps = FALSE;
public function catering() {
return $this->belongsTo('Catering');
}
}
I am able to do
$offers = Catering::find(1)->offers;
but, the inverse is not working:
$catering = Offer::find(1)->catering;
is always returning NULL. Database has the right values.
Offer table has 2 columns:
primary(id), int(cid)
that references catering.id.
The question:
How can i access the reverse side of this relation?
You said that, I am able to do
$offers = Catering::find(1)->offers;
and in your Catering model you have
public function offers() {
return $this->hasMany('Offer', 'cid');
}
It seems like you've defined a different foreign key here (cid) to use it instead of the default one that laravel basically supposed to use, so, to do the reverse relation you have to do the same thing in your Offer model's catering function
public function catering() {
return $this->belongsTo('Catering', 'cid');
}
In the Laravel Documentation, it says that, you may override the conventional foreign key by passing a second argument to the hasMany method, like
return $this->hasMany('Offer', 'custom_key');
Same way, to define the inverse of the relationship on the Offer model, you can use the belongsTo method, like
return $this->belongsTo('Catering', 'custom_key'); // cid

Categories