Get posts from multiple users in Laravel - laravel

In my site, I have a table of Users. Users can follow each other. A user can created any number of Post's.
I want to be able to see the most recent Post's from the users I've followed.
Currently my models are defined like this:
User Model:
class User extends Authenticatable
{
public function followers(){
return $this->hasMany('App\Follower', 'following');
}
public function following(){
return $this->hasMany('App\Follower', 'id');
}
public function posts(){
return $this->hasMany('App\Post', 'createdby');
}
}
Follower Model:
class Follower extends Model
{
public function postsFollowing(){
return $this->hasMany('App\Post', 'createdby', 'following');
}
}
Post Model:
class Post extends Model
{
public function user(){
return $this->belongsTo('App\User', 'createdby', 'id');
}
}
My tables are as such:
Table Name, column names
User id, name
Follower id, following
Post id, created_by
In the Follower table, id represents the user, and following represents the user being followed. If user 3 follows user 537, then id = 3, following = 537. Hope that made sense.
What I've tried:
User::following()->posts - doesn't work because
User::following() returns an Eloquent Collection object. You have
to loop through this
Looping through my followed users to get their Post's - This
doesn't work either since I want to get the top n entries sorted by
date.
Update #1
Follower Model (Updated)
class Follower extends Model
{
public function followingPosts(){
return $this->hasManyThrough(
'App\Post', 'App\Follower',
'following', 'createdby', 'id'
);
}
}
Controller
$user = Auth::user();
$posts = $user->followingPosts;
I updated followingPosts() in the Follower class with the above. The result: $posts is null
Update #2
I moved the followingPosts() to the User model:
public function followingPosts(){
return $this->hasManyThrough(
'App\Post', 'App\Follower',
'following', 'createdby'
);
}
Controller:
$user = Auth::user();
$posts = $user->followingPosts;
Now I just get all posts, even from the users I didn't follow.

Your requirement - "Users can follow each other. A user can created any number of Post's. Being able to list recent posts (limited to number) of followers or whom user is following".
You can define many-to-many relationship on the User Model (Many-To-Many relationship on self - User Model).
Create two Pivot tables
Follower-User Pivot Table
class CreateFollowerUserPivotTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('follower_user', function (Blueprint $table) {
$table->integer('follower_id')->unsigned();
$table->foreign('follower_id')->references('id')->on('users')->onDelete('cascade');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
$table->primary(['follower_id', 'user_id']);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('follower_user');
}
}
Following-User Pivot Table
class CreateFollowingUserPivotTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('following_user', function (Blueprint $table) {
$table->integer('following_id')->unsigned();
$table->foreign('following_id')->references('id')->on('users')->onDelete('cascade');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
$table->primary(['following_id', 'user_id']);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('following_user');
}
}
Then define the relationships in your User Model
class User extends Model
{
public function followers()
{
return $this->belongsToMany(User::class, 'follower_user', 'user_id', 'follower_id')->withTimestamps();
}
public function following()
{
return $this->belongsToMany(User::class, 'following_user', 'following_id', 'user_id' )->withTimestamps();
}
//Assuming posts table has user_id as foreign key
public function posts()
{
return $this->hasMany(Post::class);
}
//Assuming posts table has user_id as foreign key
public function recent_posts()
{
return $this->hasMany(Post::class)->take(10)->orderBy('created_at', 'desc');
}
}
Now to get who a given user is following
//Say for example we take the logged in user
$user = User::with('following.recent_posts')->whereEmail(auth()->user()->email);
foreach($user->following as $following)
{
$posts = $following->recent_posts;
}
Hope this is what you are trying to accomplish.

You can use has-many-through for this as:
public function followingPosts()
{
return $this->hasManyThrough(
'App\Post', 'App\Follower',
'follow', 'createdby', 'id'
);
}
Then you can access the posts as:
$user->followingPosts; // returns collection of post model
Note: Assuming you have a follow column in Follower table.

Related

Laravel : Define model for reverse OneToMany relationship

I have the following schema:
class Group extends Model
{
/**
* The users that belong to the group.
*/
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
}
What should my User model look like in the other side ?
class User extends Model
{
/**
* The group that owns the user.
*/
public function group()
{
return $this->???(Group::class)->withTimestamps();
}
}
It's also a belongsToMany, just the inverse. Try this paradigm:
return $this->belongsToMany(
'App\Models\Group',
'user_group',
'user_id',
'group_id'
)->withTimestamps();
Where the explicit params are:
Related Model
Table (Pivot table)
Foreign Pivot Key
Related Pivot Key

Strange behavior on laravel many to many relationship

I have two models User and Tenant and in my project, a User can have many Tenants connected to him and Tenant can have many users connect to him.
This is my User model
public function tenants()
{
return $this->beLongsToMany(\App\Models\TenantsUsers::class, 'tenants_user', 'user_id', 'tenant_id');
}
This is my Tenant model
public function users()
{
return $this->beLongsToMany(\App\Models\TenantsUsers::class, 'tenants_user', 'tenant_id', 'user_id');
}
And this is my TenantsUsers model
class TenantsUsers extends Model
{
use UtilTrait;
use Notifiable;
protected $table = 'tenants_user';
protected function serializeDate(DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'user_id' => 'integer',
'tenant_id' => 'integer'
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
**/
public function tenants()
{
return $this->hasMany(\App\Models\Tenant::class, 'tenant_id');
}
public function users()
{
return $this->hasMany(\App\Models\User::class, 'user_id');
}
When I execute this function from the repository:
$userTemp = $this->userRepository->with(['tenants'])->findWhere(['email' => $userEmail])->first();
And I'm getting this error :
SQLSTATE[42712]: Duplicate alias: 7 ERROR: table name "typo_tenants_user" specified more than once (SQL: select
"typo_tenants_user".*, "typo_tenants_user"."user_id" as "pivot_user_id", "typo_tenants_user"."tenant_id" as
"pivot_tenant_id" from "typo_tenants_user" inner join "typo_tenants_user" on "typo_tenants_user"."id" =
"typo_tenants_user"."tenant_id" where "typo_tenants_user"."user_id" in (1))
What I'm doing wrong?
You don't need to create a model for pivot tables in Eloquent many-to-many relationships. Instead, use the related model's class when defining the relationship:
// User model
public function tenants()
{
return $this->belongsToMany(\App\Models\Tenant::class, 'tenants_user', 'user_id', 'tenant_id');
}
// Tenant model
public function users()
{
return $this->belongsToMany(\App\Models\User::class, 'tenants_user', 'tenant_id', 'user_id');
}
If you follow Eloquent naming conventions by defining the pivot table as tenant_user rather than tenants_user, things can be even further simplified to:
// User model
public function tenants()
{
return $this->belongsToMany(\App\Models\Tenant::class);
}
// Tenant model
public function users()
{
return $this->belongsToMany(\App\Models\User::class);
}

I want to return a user with a list of all the people they have referred by there username

I am developing a referral system in my software. I have gotten the referral right but I want to list all users the auth users have referred.
Note: I am writing an API endpoint so I cant use a relationship to display their name.
Here is my user model
public function referrals()
{
return $this->hasMany(Referral::class, 'user_id', 'id');
}
public function referrer()
{
return $this->hasOne(Referral::class, 'referred_by', 'id');
}
Note: referred_by is the person that has referred someone and user_id is the person referred
Here is my referral model
protected $fillable = ['user_id', 'referred_by', 'status'];
public function user()
{
return $this->belongsTo(User::class);
}
Here is my referrals migration
Schema::create('referrals', function (Blueprint $table) {
$table->id();
$table->integer('user_id')->unsigned()->references('id')->on('users');
$table->integer('referred_by')->unsigned()->references('id')->on('users');
$table->string('status')->nullable();
$table->timestamps();
});
User Model
// Referrals given by the user.
public function referralsGiven()
{
return $this->hasMany(App\Referral::class, 'referred_by', 'id');
}
Referral Model
//Person who got the referral
public function user()
{
return $this->belongsTo(App\User::class, 'user_id', 'id');
}
public function referredBy()
{
return $this->belongsTo(App\User::class, 'referred_by', 'id');
}
pluck collection method https://laravel.com/docs/7.x/collections#method-pluck
Controller
$user = User::with('referralsGiven.user')->find(Auth::user()->id);
$users_reffered_by_Auth_user = $user->referralsGiven->pluck('user');
OR
$referrals = Referral::with('user')->where('reffered_by', Auth::user()->id)->get();
$users_reffered_by_Auth_user = $referrals->pluck('user');

Display values of a list table in eloquent using laravel 5

I have this table with 4 id's related to other tables.
Table List:
id table1_id table2_id table3_id table4_id
1 2 3 2 1
2 1 4 3 3
I want now to output the values related to that table's ids
id table1_name table2_name table3_name table4_name
1 jay student singer actor
2 jeane teacher drummer actress
ListController:
public function index()
{
$res = ListModel::with('table1','table2','table3','table4')->get();
$foreach($res as r){
return $r->table1_name;
}
return view('list.index',compact('res'));
}
My problem here is that the output will be null instead of jay.How can I display now the values?Please help..
list table
public function up()
{
Schema::create('list_table', function (Blueprint $table) {
$table->increments('id');
$table->string('table1_id');
$table->string('table2_id');
$table->string('table3_id');
$table->string('table4_id');
$table->timestamps();
});
}
//additional info
Table1 Model
public function list(){
return $this->belongsTo('App\ListModel');
}
List Model
public function table1(){
return $this->hasMany("App\Table1",'id','table1_id');
}
Updated Values
id crime_type_id crime_name_id crime_suspect_id crime_victim_id
1 1 1 1 1
Expected output:
crime_type_des crime_name_des crime_suspect_name victim_name
against property theft Mcdonald Hillary
ReportController:
public function index()
{
$display_crime = CrimeReport::all();
return view('crimereports.index',compact('display_crime'));
}
report_table:
public function up()
{
Schema::create('crime_reports', function (Blueprint $table) {
$table->increments('id');
$table->string('crime_type_id');
$table->string('crime_name_id');
$table->string('suspect_id');
$table->string('victim_id');
$table->timestamps();
});
}
//additional info
CrimeName Model
public function crimeReport(){
return $this->belongsTo('App\CrimeReport');
}
Crime Report Model
public function crimeName(){
return $this->hasMany("App\CrimeName",'id','crime_name_id');
}
//Rest for CrimeReportController
public function index()
{
$display_crime = CrimeReport::all();
return view('crimereports.index',compact('display_crime'));
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
$display_crime_type = CrimeType::lists('crime_type','id');
$display_crime_name = CrimeName::lists('crime_description','id');
return view('crimereports.create',compact('display_crime_type','display_crime_name'));
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(CrimeNewReportRequest $request)
{
$input = $request->all();
CrimeReport::create($input);
return redirect()->back()->withSuccess("Fields were inserted!");;
}
Change your relation definition as below:
Table1 Model
public function list(){
return $this->hasMany('App\ListModel');
}
List Model
public function table1(){
return $this->belongsTo("App\Table1");
}
You need update your index method as below, you could dump $rows to check if this work.
ListController
public function index()
{
$res = ListModel::with(['table1','table2','table3','table4'])->get();
$rows = [];
$foreach($res as r) {
$rows[] = [r->table1->name, r->table2->name, r->table3->name, r->table4->name];
}
dd($rows);
}
Your accessing table1_name on the original model change the _ to -> ( $r->table1->name)
EDIT:
Now it's starting to become much more readable. Here are what I think the relationships should be.
CrimeReport.php
public function crimeType()
{
return $this->belongsTo(CrimeType::class);
}
public function crimeName()
{
return $this->belongsTo(CrimeName::class);
}
public function suspect()
{
return $this->belongsTo(Suspect::class);
}
public function victim()
{
return $this->belongsTo(Victim::class);
}
There really doesn't seem to be a need to define the inverse of any of there relationships right away, if the need arises later then add them but there is no point creating the relation just because its there.
Now to make showing the report easy lets use some joins instead or eager loading.
CrimeReportController.php
public function index()
{
$results = CrimeReport::query()
->join('crime_types as ct','ct.id', '=', 'crime_reports.crime_type_id')
->join('crime_names as cn','cn.id', '=', 'crime_reports.crime_name_id')
->join('suspects as s','s.id', '=', 'crime_reports.suspect_id')
->join('victims' as v','v.id', '=', 'crime_reports.victim_id')
->get([
'crime_report.*', //to get ids and timestamps
'ct.name as crime_type',
'cn.name as crime_name',
'suspect.name as suspent_name',
'victim.name as victim_name'
])
dd($results->toArray());
}
Now $results will still be a collection of CrimeReport so you can still have access to all the model goodies you might want to throw in there. In addition to that you also already have your table, you can just print these out into an html table and you have your report.
If you were wanted to add some cool search stuff to the query then you can use whereHas to do that:
//this would just go before the get()
$query->whereHas('suspect', function($q){
$q->where('hair_color','=','brown')
->whereBetween('height',5.8,6)
})
Of course you might also want to make some of those leftJoins instead since I assume they won't all have a victim/suspect

How to make user, and roles relationship in Laravel 5

I have two tables :
User ->
id :
name :
role_id : ->references('id')->on('roles');
Roles ->
id :
role_name :
access :
I am trying to access roles details from user.
My User model has:
public function role()
{
return $this->belongsTo('App\Role');
}
My Role model has:
public function user()
{
return $this->hasMany('App\User');
}
When I try to do following :
$user = User::find(1);
$details = [
'name' => $user->first_name,
'role' => $user->role->role_name
];
I get error :
Trying to get property of non-object
My roles table contains access columns containing array of permissions to different routes. So my user will have only one role. While a role can have multiple users.
How to do that?
In my recent project, I handled these requirement in that way..
First of All Database Table Structure/Migration
User Table
class CreateUserTable extends Migration {
public function up() {
Schema::create('user', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password', 60);
$table->boolean('status')->default(0);
$table->boolean('is_admin')->default(0);
$table->boolean('notify')->default(0);
$table->rememberToken();
$table->timestamps();
});
}
public function down() {
Schema::drop('user');
}
}
Role Table
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateRoleTable extends Migration {
public function up()
{
Schema::create('role', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->string('display_name')->nullable();
$table->string('description')->nullable();
$table->boolean('status')->default(0);
$table->timestamps();
});
}
public function down()
{
Schema::drop('role');
}
}
Role And User Relation Table
class CreateRoleUserTable extends Migration {
public function up() {
// Create table for associating roles to users (Many-to-Many)
Schema::create('role_user', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->foreign('user_id')->references('id')->on('user')
->onUpdate('cascade')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('role')
->onUpdate('cascade')->onDelete('cascade');
$table->primary(['user_id', 'role_id']);
});
}
public function down() {
Schema::drop('role_user');
}
}
After these table you have to handle permission by assigning to specific Role.
Permission
class Permission extends Migration {
public function up() {
Schema::create('permission', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->string('pattern');
$table->string('target');
$table->string('module');
$table->string('display_name')->nullable();
$table->boolean('status')->default(0);
$table->timestamps();
});
}
public function down() {
Schema::drop('permission');
}
}
Permission and Role Table Relation
class PermissionRole extends Migration {
public function up() {
// Create table for associating roles to permission (Many-to-Many)
Schema::create('permission_role', function (Blueprint $table) {
$table->integer('permission_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->foreign('permission_id')->references('id')->on('permission')
->onUpdate('cascade')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('role')
->onUpdate('cascade')->onDelete('cascade');
$table->primary(['permission_id', 'role_id']);
});
}
public function down() {
Schema::drop('permission_role');
}
}
And Finally our model would look alike:
User Model
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
protected $table = 'user';
protected $fillable = ['name', 'email', 'password', 'is_admin'];
protected $hidden = ['password', 'remember_token'];
public function scopeActive($query) {
return $query->whereStatus('1');
}
public function scopeAdmin($query) {
return $query->whereIsAdmin('1');
}
public function scopeNotify($query) {
return $query->whereNotify('1');
}
public function roles() {
return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
}
public function attachRole($role) {
if (is_object($role)) {
$role = $role->getKey();
}
if (is_array($role)) {
$role = $role['id'];
}
$this->roles()->attach($role);
}
public function detachRole($role) {
if (is_object($role)) {
$role = $role->getKey();
}
if (is_array($role)) {
$role = $role['id'];
}
$this->roles()->detach($role);
}
public function attachRoles($roles) {
foreach ($roles as $role) {
$this->attachRole($role);
}
}
public function detachRoles($roles) {
foreach ($roles as $role) {
$this->detachRole($role);
}
}
public function isSuperUser() {
return (bool)$this->is_admin;
}
public function hasAccess($permissions, $all = true) {
if ($this->isSuperUser()) {
return true;
}
return $this->hasPermission($permissions, $all);
}
public function hasPermission($permissions) {
$mergedPermissions = $this->getMergedPermissions();
//dd($mergedPermissions);
if (!is_array($permissions)) {
$permissions = (array)$permissions;
}
foreach ($permissions as $permission) {
$matched = false;
// We will set a flag now for whether this permission was
// matched at all.
$founded_perms = find_in($mergedPermissions, "name", $permission);
if (!empty($founded_perms)) {
$matched = true;
}
}
if ($matched === false) {
return false;
}
return true;
}
public function getMergedPermissions() {
$permissions = array();
foreach ($this->getRoles() as $group) {
$permissions = array_merge($permissions, $group->permissions()->get()->toArray());
}
return $permissions;
}
public function getRoles() {
$roles = [];
if ($this->roles()) {
$roles = $this->roles()->get();
}
return $roles;
}
}
Role Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'role';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'display_name', 'description'];
public function scopeActive($query) {
return $query->whereStatus('1');
}
/**
* Many-to-Many relations with User.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function users() {
return $this->belongsToMany('App\User');
}
public function permissions() {
return $this->belongsToMany("App\Permission");
}
}
Permission Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Permission extends Model {
protected $table = 'permission';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'pattern', 'target', 'module', 'display_name', 'status'];
public static function displayable() {
$prepared_array = [];
$temp = self::orderBy('module')->get()->toArray();
foreach ($temp as $sin) {
$prepared_array[$sin['module']][] = $sin;
}
return $prepared_array;
}
public function scopeActive($query) {
return $query->whereStatus('1');
}
public function roles() {
return $this->belongsToMany("App\Role");
}
}
Well, thats the basic structure helped to implement basic ACL and Auth with laravel 5.
Let me know if you have any further related question. Or If you need complete implementation I'll provide it to you.
For a one-to-many relationship you don't need a pivot table, so you can delete the user_roles table. Then add a role_id column to your users table, that will reference the id column in for your roles table. Next define the relations as follows for each of your models:
// User.php
public function role()
{
return $this->belongsTo('App\Role');
}
and
// Role.php
public function users()
{
return $this->hasMany('App\User');
}
Now you can access your role via the relation like this:
$user->role->name;
I got the problem, i was having a role column in user table, so when i was doing
$user->role->role_name
it was fetching role column instead of relationship.
i noticed you are not using the laravel default table naming conventions,
you are using user_roles whereass laravel naming conventions state you should use:
role_user (alphabetical and singular)
you could override the belongsToMany by stating your custom table name ofcource.
public function users() {
return $this->belongsToMany('App\User', 'user_roles');
}
on the second node there are also some good libraries to handle these kind of things, take a look at : https://github.com/romanbican/roles

Resources