I have a blog built with laravel.
and I want to add likes to my posts.
so I created a Like model with a likes table.
this is what i have done in my Like model
public function post(){
return $this->belongsTo(Post::class);
}
public function user(){
return $this->belongsTo(User::class);
}
in my Post and User models
public function likes(){
return $this->hasMany(Like::class);
}
and my migration file for likes table
Schema::create('likes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreign('post_id')->references('id')->on('posts');
$table->foreign('user_id')->references('id')->on('users');
$table->boolean('value');
$table->timestamps();
});
I want to set the values in my controller on this way!
public function liker($postID, $userID, $value){
$like = new Like([
'post_id' => $postID,
'user_id' => $userID,
'value' => $value
]);
$like->save();
return redirect()->back();
}
but the view return 419 error page. (Page Expired)
and also no changes (no row) adds to my database(likes table)!
can you help me?
you dont need value on a like, if it exists, it's a "like" and you should use is as a pivot table (you already have 2 foreign IDs in it)
Schema::create('likes', function (Blueprint $table) {
$table->unsignedInteger('post_id');
$table->unsignedInteger('user_id');
$table->foreign('post_id')->references('id')->on('posts');
$table->foreign('user_id')->references('id')->on('users');
$table->tinyInteger('is_dislike')->default(0);
$table->timestamps();
});
then declare the relation between Post and User
Post
public function votedUsers(){ //or simply likes
return $this->belongsToMany(User::class, 'likes')->withPivot('is_dislike')->withTimestamps();
}
User
public function votedPosts(){
return $this->belongsToMany(Post::class, 'likes')->withPivot('is_dislike')->withTimestamps();
}
Next to create a like just do it like this
public function liker($postId, $userId, $value){
$user = User::findOrFail($userId); //or use auth()->user(); if it's the authenticated user
$user->votedPosts()->attach($postId);
return redirect()->back();
}
to Remove a like use detach($postId) instead.
For dislike
$user->votedPosts()->attach($postId, ['is_dislike' => 1]);
Related
I have a One To Many relationship between User Model & Order Model:
User.php:
public function order()
{
return $this->hasMany(Order::class);
}
Order.php:
public function user()
{
return $this->belongsTo(User::class);
}
Now I need to access user instance from order:
$order = Order::where('id', $id)->update(['status' => 'verified', 'price' => $data['price']]);
$user = $order->user;
dd($user);
But in this way, I get this error:
Trying to get property 'user' of non-object
So how to solve this issue and access user instance properly?
Here is the Migration of orders table:
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('material');
$table->string('color');
$table->string('dimensions');
$table->string('description')->nullable();
$table->tinyInteger('user_id')->unsigned()->nullable();
$table->timestamps();
});
update method wont return order detail's because update return true or false. So change it to
$order = Order::find($id);
$order->status='verified';
$order->price=$data['price'];
$order->save();
$user = $order->user;
update method takes array as argument update(array $values) and return int
Why don`t you add in the migration the relation as a foreignID?
$table->foreignID('user_id')->constrained();
I would like to build 'likes' functionality in my app where one user (user1) can like another user (user2), and then if user2 likes back user1 they would match. What is the best way to implement that kind of logic? My current idea is something like this.
users_table
public function up()
{
Schema::create('users', function(Blueprint $table)
{
$table->increments('id');
$table->string('email');
$table->string('first_name');
$table->string('last_name');
$table->string('password', 60);
$table->rememberToken()->nullable();
$table->timestamps();
});
}
likes_users_table
public function up()
{
Schema::create('likes_users', function(Blueprint $table)
{
$table->integer('liked_user_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('liked_user_id')->references('id')->on('users');
$table->primary(array('user_id', 'liked_user_id'));
});
}
User.php
public function likes()
{
return $this->belongsToMany('User', 'likes_users', 'user_id', 'liked_user_id');
}
UserController.php
public function getIndex()
{
$not_friends = User::where('id', '!=', Auth::user()->id);
if (Auth::user()->likes->count()) {
$not_friends->whereNotIn('id', Auth::user()->likes->modelKeys());
}
$not_friends = $not_friends->get();
return View::make('dashboard.index')->with('not_friends', $not_friends);
}
public function add(User $user)
{
$user->likes()->attach($user->id);
}
public function store($id)
{
$user = User::find($id);
Auth::user()->add($user);
return Redirect::back();
}
This is a quick solution. There could be a more efficient way to accomplish this. Suggestions welcome.
My idea is to set a is_mutual flag for user likes. If the users like each other the is_mutual flag will be set.
Let's start with the migration.
Create user_likes table.
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('user_likes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id')->comment('user who liked this');
$table->unsignedBigInteger('liked_user_id')->comment('user whom this liked');
$table->boolean('is_mutual')->default(false)->comment('is users like each other');
$table->timestamps();
$table->softDeletes();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('liked_user_id')->references('id')->on('users');
});
}
Then, I have updated my User model to add the following relations
public function likedUsers()
{
return $this->belongsToMany('App\User', 'user_likes', 'user_id', 'liked_user_id');
}
public function mutualFriends()
{
return $this->belongsToMany('App\User', 'user_likes', 'user_id', 'liked_user_id')
->where('is_mutual',1);
}
Now Let's create a controller to handle the User Likes logic.
public function storeUserLikes(Request $request)
{
$user = Auth::user(); // Take the currently authenticated user
// Ofcourse, you should validate the $request
$likedUser = $request->likedUser;
// Let's findout if the other user already likes the current user
$isLikedAlready = UserLike::where([
'user_id' => $likedUser,
'liked_user_id' => $user->id,
])
->first();
// Store the user like record in the db
UserLike::create([
'user_id' => $user->id,
'liked_user_id' => $likedUser,
'is_mutual' => $isLikedAlready ? true : false
]);
// If the other user already likes the current user,
// they are a mutual connection.
// Update the row accordingly
if ($isLikedAlready) {
$isLikedAlready->is_mutual = true;
$isLikedAlready->save();
}
// Done! Now show a proper response to the User.
// I am leaving it to you :-)
}
Now, let's add the routes
Auth::routes();
Route::group(['prefix' => 'user', 'middleware' => 'auth'], function ($router) {
$router->get('/like-user/{likedUser}', ['uses' => 'UserLikesController#storeUserLikes']);
});
Now, add some users to your database (for testing). Refer Laravel database seeding and factory for more details.
How it works
The logged-in user can go to DOMAIN/user/like-user/x to like a user.
Where x is the id of the User to be liked.
Note: I have added a get route for ease. You can use POST/GET methods of your choice.
Now, Let's find a list of mutual friends from the DB
Add a function to the UserLikes controller.
/**
* This function will return a JSON Response with mutually liked users
* for the current logged in user.
**/
public function listLikedUsers()
{
$user = Auth::user();
return response()->json([
'status' => true,
'data' => $user->mutualFriends()->get()
]);
}
Now add a route for getting the mutually liked users. Just below the current route add the following GET route
$router->get('/likes', ['uses' => 'UserLikesController#listLikedUsers']);
You can have a pivot boolean column (is_liked_back) in likes_users table. In this way you will only have one entry for likes getting from either side.
I am making FollowController where I have two tables following_users table and following_user_item table. which is in hasMany relationship. When a authenticate current_user wants to follow an user, the ID of the user will stored in following_users table and its relational table stored the current_user_id and the following_user_id (which is the id of following_users table). here is the schema.
following_users_table:
public function up()
{
Schema::create('following_users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')
->references('id')
->on('users');
$table->timestamps();
});
}
following_user_item_table:
public function up()
{
Schema::create('following_user_items', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('following_users_id')->unsigned();
$table->foreign('following_users_id')
->references('id')
->on('following_users');
$table->bigInteger('user_id')->unsigned();
$table->timestamps();
});
}
I have done the FollowController but the problem is comming when try to check whether the user is already followed or not.
Follow Relationship in User model
public function followingUserList()
{
return $this->hasOne('App\FollowingUser');
}
/**
* Get the stories associated with the user through an intermediate table
*
*/
public function followingUsers()
{
return $this->hasManyThrough(
'App\FollowingUserItem',
'App\FollowingUser',
null,
'following_users_id'
);
}
FollowingUser Model Relationship with User and FollowingUserItem
public function user()
{
return $this->belongsTo('App\User');
}
public function users()
{
return $this->hasMany('App\FollowingUserItem','following_users_id');
}
Here is my FollowController:
class FollowController extends Controller
{
//
public function index($id)
{
$user = User::find($id);
$logged_userId = Auth::User();
if ($user->id == $logged_userId->id) {
return [
'status' => false,
'message' => 'You can not Follow yourself',
];
}
if ($user && $logged_userId) {
$checkUsers = FollowingUser::where('user_id', $user->id)->get()->users()->where('user_id', $logged_userId->id);
if ($checkUsers)
{
return 'already followed';
}
else
{
$user->followingUserList()->save(new FollowingUser())->users()->save(new FollowingUserItem(['user_id' => $logged_userId->id]));
return 'sucess';
}
}
}
}
I go the error
Method Illuminate\Database\Eloquent\Collection::users does not exist.
When you call get() Laravel returns a collection as it does not know how many rows there will be there. This is why you get collection does not have users set error. Since you filter on an id you know there is only gonna be one, therefor you can utilize the first() method.
So change the code to use first().
$checkUsers = FollowingUser::where('user_id', $user->id)->first()->users()->where('user_id', $logged_userId->id);
I have 4 tables, 1->user, 2->category, 3->comment, 4->post
I want to get the category for the related post that user already commented
SELECT kategoris.* FROM kategoris
INNER JOIN yazis on yazis.kategori_id = kategoris.id
INNER JOIN yorums on yorums.yazi_id = yazis.id
INNER JOIN users on users.id = yorums.user_id
where users.id = 1
Relations
Depending on how your models are setup, this is how the query should be with Eloquent
$category = Post::whereHas('comments', function($query) {
$query->where('user_id', auth()->user()->id);
})->first()->category;
Update:
This is how your models and table migrations should look
User has many posts and comments
public function posts()
{
return $this->hasMany(Post::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
Category has many posts
public function posts()
{
return $this->hasMany(Post::class);
}
Post belongs to a category and a user, has many comments
public function category()
{
return $this->belongsTo(Category::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
Posts Table Migration
Schema::create('posts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignedBigInteger('category_id');
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->timestamps();
});
Comment belongs to a post and a user
public function post()
{
return $this->belongsTo(Post::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
Comments Table Migration
Schema::create('comments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignedBigInteger('post_id');
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->timestamps();
});
Let's populate some data like this...
Database Seeder
$user = factory(User::class)->create([]);
$category = Category::create([]);
$post = $user->posts()->create(['category_id' => $category->id]);
$post->comments()->create(['user_id' => $user->id]);
And get the category of the post that the authenticated user commented on with the query above...
Hope this helps :)
I'm trying to give ability on user to see his orders. I have created relationships but when i (dd) the result of the function, the related model attributes are empty.
I don't know what is wrong.
Here is my buyer function
//Buyer Orders
public function myOrders()
{
$user = User::find(auth()->user()->id);
$user = $user->products();
dd($user);// related model attributes shows empty
return view('myOrders')->with(compact('user'));
}
and here is my user
public function products()
{
return $this->hasMany(Products_model::class);
}
public function orders()
{
return $this->hasMany(Order::class);
}
public function allOrdersBuyerSeller()
{
return $this->hasMany(OrderProduct::class);
}
products_model
public function orders()
{
return $this->belongsToMany('App\Order', 'order_product');
}
public function user()
{
return $this->belongsTo('App\User');
}
User Migration
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
Product Migration
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('pro_name');
$table->integer('pro_price');
$table->text('pro_info');
$table->integer('stock');
$table->integer('category_id');
$table->string('image')->nullable();
$table->timestamps();
$table->bigInteger('seller_id')->unsigned()->index();
$table->foreign('seller_id')->references('id')->on('users')->onDelete('cascade');
});
}
I would like to see the attributes of the table like price, name, info, img and etc.
Barring the comments about your code, the reason you're not seeing the result of your products query is that you're not passing a closure to the query.
$user = $user->products();
Currently, $user is a QueryBuilder instance. Until you use a closure, like first(), get(), paginate(), etc, you won't be able to see the rows. Modify your code to the following:
$products = $user->products;
// OR
$products = $user->products()->get();
If you omit the (), it will load the relationship using products()->get(), unless already loaded.
Edit: You likely need to include foreign keys to your relationships as the Model name won't match:
User.php
public function products(){
return $this->hasMany(Product_model::class, "seller_id", "id");
}
Probably best to review the contents of the documentation for Relationships; https://laravel.com/docs/5.8/eloquent-relationships. There's a lot of incorrect practices going on with your naming, querying, etc.