Laravel - Friendship - php

I'm trying to do a friendship system in laravel 5 and I'm stuck.
I have a friends_user table which look like this:
id
user_id
friend_id
status
Here is the point, I go to an user page, and Ii wanna see how is my relation with this user, 4 solutions:
We are friends
We're not
He doesn't have accepted the request yet
I have to confirm or not.
I wanna create a method that checks if a user is friend with an other, simple.
I have a 'status' column which is a boolean (0 for pending and 1 for friends)
The perfect solution for me would be to be able in one method to check if:
The users are friend, so either ('user_id', Auth::user()->id)->and ('friend_id', $friend->id) or the inverse ('user_id', $friend->id)->and ('friend_id', Auth::user()->id), it has to check in the 2 senses
I sent request and have to wait for his answer
I received the request and have to accept it.
We're not friend and so, i can add him.
So if you can tell me where i'm wrong here, here's my logic (just for check if users are friend) : User.php
public function isFriend($slug)
{
// Get both user
$user = Auth::user();
$receiver = User::where('slug', $slug)->first();
// get list of friends (so who have status = 1)
$result = Friends::where('status', 1);
// Get users where user id is equal to connected
$result = $result->where('user_id', $user->id)->where('friend_id', $receiver->id);
$result = $result->orWhere('user_id', $receiver->id)->where('friend_id', $user->id);
$result = $result->get();
if(count($result) == 0)
return false;
return true;
}
After I do these checks in my view.
This works pretty much, but only if i (the current user) has sent the request but if it's the inverse it returns me the user even if status is at 0. I think that my $result erase the other ones isn't it? What's the solution so?
I hope it's clear, and if you can tell me how do this in a clean way, it would be great.

That's a common mistake. Beware of your "orWhere" clause.
public function isFriend($slug)
{
// Get both user
$user = Auth::user();
$receiver = User::where('slug', $slug)->first();
// get list of friends (so who have status = 1)
$result = Friends::where('status',1)->where(function($query) use ($receiver,$user)
{
$query->where([
'user_id' => $user->id,
'friend_id' => $receiver_id
])->orWhere([
'user_id' => $receiver->id,
'friend_id' => $user->id
]);
})->get();
return ! $result->isEmpty();
}

Related

Laravel - Use conditions when selecting data using controllers

I have the following controller where I try to select all the customers of a user (The ones with 'user_id' equal to the 'id' of the authenticated user). I know how to do it in the following way, but as you can see it is not very efficient since it selects more records than necessary.
public function index() // Http/Controllers/CustomerController.php:17
{
$user_id = Auth::id(); // Get user ID
$customers = Customer::all()->where('user_id', $user_id); // Select all users and then filter by ID
return $this->showAll($customers, 200); // Return JSON response with response code
}
Change your $customers = Customer::all()->where('user_id', $user_id); to:
$customers = Customer::where('user_id', $user_id)->get();
https://laravel.com/docs/7.x/eloquent#retrieving-models

Laravel multi condition query

I want to search for users previous relations but not sure how to make this logic happen.
Logic
My table has 2 columns from_id to_id (both will get users ids)
I am sending 2 ids to back-end (one as input, another one in request header)
I want to say: whereinput id is from_id and header id is to_idORwhere input id is to_id and header id is from_id` return the result otherwise is null obviously.
Note:
The part that I'm stuck in is and in conditions input id is from_id and header id is to_id OR where input id is to_id and header id is from_id
Code
currently I have half way code which is this:
public function check(Request $request) {
// user id from header request (request sender) e.g `1`
$user = $request->user();
// second user id (not sure where to use it yet) e.g `4`
$request->input('receiverId');
$chat = PrivateChat::where('from_id', $user->id)->orWhere('to_id', $user->id)->first();
}
To make it simple
Basically I want return old chat between the 2 ids regardless of who was sender (from_id) and who was receiver (to_id).
Any idea how to make my logic happen?
Update
this is my full code and it always return false while i do have previous chat between users with id 1 and 4.
public function check(Request $request) {
$user = $request->user();
$chat = PrivateChat::where([['from_id', $user->id],['to_id',$request->input('receiverId')]])
->orWhere([['from_id', $request->input('receiverId')],['to_id',$user->id]])->first();
$receiver = User::where('id', $request->input('receiverId'))->first();
if($chat) {
return response()->json([
'data' => new PrivateChatResource($chat),
'exist' => true,
'receiver' => new UserResource($receiver),
'message' => 'Chat data retrieved successfully.'
]);
} else {
return response()->json([
'exist' => false,
'receiver' => new UserResource($receiver),
'message' => 'Chat data retrieved successfully.'
]);
}
}
As i see it you want to do the boolean logic, if wrong please correct me.
(from_id = header_id AND to_id = header_id) OR (from_id = input_id AND to_id = input_id)
This can be obtained with the following Eloquent query. Using where($cloure) syntax, for doing the boolean logic listed above. Calling where with a closure, adds parenthesis to your logic, everything within the clojure will be wrapped in ().
$user = $request->user();
$userInput = $request->input('receiverId');
PrivateChat::where(function ($query) use ($user) {
$query->where('from_id', $user->id)->orWhere('to_id', $user->id);
})->orWhere(function ($query) use ($userInput) {
$query->where('from_id', $userInput)->orWhere('to_id', $userInput);
})->first();
If i understand correctly your where logic looks like this:
('from_id' = $user->id & 'to_id' = $request->input('receiverId'))
|| ('from_id' = $request->input('receiverId') & 'to_id' = $user->id)
You can define multiple conditions in a single where:
PrivateChat::where([['from_id', $user->id],['to_id',$request->input('receiverId')]])
->orWhere([['from_id', $request->input('receiverId')],['to_id',$user->id]])->first();
->first() will return the first record that meets one of the conditions, but if you want all results you can use ->get().

Query in Yi2 and checking a relationship in another table

I am trying to get data in a Yii2 table call Post. This table has an attribute call owner and I want to check whether the value of owner is equal to a particular Value I pass call it userId or the value of owner is equal to the following attribute of the Followship table where the value of the follower attribute of the Followship Table is equal to the the value I pass call it userId.
In implementing the above logically and bit by bit, I have written the following code;
$allpost = Post::find()->all();
$relevantpost = [];
foreach ($allpost as $post) {
if($post->owner == $userId){
$relevantpost[] = $post;
}
else{
$follower = Followship::findOne(['follower'=>$userId, 'following'=>$post->owner]);
if($follower){
$relevantpost[] = $post;
}
}
}
return $relevantpost;
This code works well but I want to write an active query for this such as ;
$allpost = Post::find()
->where(['owner'=>$userId])
->orWhere(['is NOT', $follower = Followship::findOne(['follower'=>$userId]) and 'owner' => $follower->following, NULL])
->all();
or in the worse case,
$allpost = \Yii::$app->db
->createCommand(
"SELECT postId, location, details, created_at FROM Post
WHERE owner = " . $userId. "OR
owner = '0' OR
owner = following IN (
SELECT following FROM Followship WHERE follower = ". $userId . " AND
)
ORDER BY dateCreated DESC"
)
->queryAll();
I keep getting errors with the above queries. I am missing out a fundamental of the Yii2 query builders.
Please any help on this will be greatly appreciated.
First you could make a relation (which connects Post and Followers by post owner) inside your Post class
class Post extends ActiveRecord {
public function getFollowersDataset() {
return $this->hasMany(Followers::className(), ['following' => 'owner']);
}
...
}
And then you can just use it in your queries
Post::find()
->joinWith('followersDataset')
->where(['or',
['owner' => $user_id],
['follower' => $user_id]])
->all()
The condition accept three parameters
[the_condition, the_attribute, the_value]
In case of AND and OR the thing change
[the_condition, first_condition, second_condition]
With the second tried you can make something like that
$allpost = Post::find()
->where(['owner'=>$userId])
->orWhere([
'AND',
['is NOT', $follower, Followship::findOne(['follower'=>$userId]),
['owner', $follower->following, NULL]
])
->all();
You can check in debug bar the querys that you're making, or another way, its to make a mistake in a field, for example if in your where condition you put ->where(['owners'=>$userId]), that trhow an error with the query that you made, so you can see what query you did

Laravel 5.4 eloquent hasMany and subsequent PHP to check an approval status

I have two models, Email and EmailReview. Email hasMany EmailReviews. This query:
$data = Email::with('emailReviews')->where('created_by', '=', $personId)->get();
returns a collection of a specific person's emails that have a review_group_type of either approval or feedback and a relationship of email_reviews that have an approved property of either true, false or null. I'm looking for the cleanest way to check if the email is an approval email and all of the reviews in the collection have their approved column set to true in order to set an approval status for each email i.e., $email->approvalStatus. Some emails will also not have reviews yet, so I'll need to check for that. Something along these lines, but it's clearly getting ugly and I'm having a hard time getting my end result:
if ($data->review_group_type === 'approval') {
foreach($data as $email) {
if (!is_null($email->email_reviews))
foreach($email->email_reviews as $review) {
}
}
}
Building on #Salama96 response and going a little bit further, you can do this:
$data = Email::with('emailReviews')
->where(['created_by'=>$personId,'review_group_type'=>'approval'])
->has('emailReviews')
->get()
->map(function ($email){
// Here, you check if all the emailReviews are 'true'
$reviewsStatus = $email->emailReviews->pluck('approved')->unique();
if ($reviewsStatus->count() == 1 AND $reviewsStatus->first())
{
$email->approvalStatus = true;
}
return $email;
});
}
PS: Haven't test it properly, but it should work.
I think you can simplify your query to be like this :
$data = Email::with('emailReviews')
->where(['created_by'=>$personId,'review_group_type'=>'approval'])
->has('emailReviews')->get();
Here you are going to get all emails created by specific person with an approval condition and have emailReviews

How do I retrieve data in INT form from a database with codeigniter?

I am trying to create an update function that adds an entered value to the value for the user in a database. (It adds accounts that can be used for a class to a teacher) So far, I have a test button that should add one account when it's clicked and then refresh the page.
Here is my function thus far:
public function add_account()
{
$this->load->model("teacher_data_model");
$user = $this->ion_auth->user()->row();
$user_id = $user->id;
$data = array(
'user_id' => $user_id,
'unused_accounts' => [what do I insert here?]
);
$this->teacher_data_model->add_accounts($data, $user_id);
redirect('teacher', 'refresh');
}
This function is admittedly sloppy, I am still fairly new to this. This function gets the user ID and passes it to a model that uses it to find our teacher and update the number of student accounts they have. So far this works as long as I have a fixed value for 'unused_accounts', the problem is when I do this:
public function add_account()
{
// Getter of the user data
$user = $this->ion_auth->user()->row();
$user_id = $user->id;
$this->load->model("teacher_data_model");
//This gets the existing accounts
$num_accounts["record"] = $this->teacher_data_model->get_unused_accounts($user_id);
$this->load->view("teacher/teacher_data_viewer", $num_accounts);
$data = array(
'user_id' => $user_id,
'unused_accounts' => [what do I insert here?]
);
// data insertion
$this->teacher_data_model->add_accounts($data, $user_id);
redirect('teacher', 'refresh');
}
I'm not sure whether to but the +1 increment in the controller or the model, but I can't even seem to identify the searched data as an int at this point.
For [what do I insert here?] if I use $num_accounts I get this database error:
Error Number: 1054
Unknown column 'Array' in 'field list'
UPDATE teachers SET user_id = '1', unused_accounts = Array WHERE user_id = '1'
Here is my model in case it's needed:
function add_accounts($data, $uid)
{
$this->db->where('user_id', $uid);
$this->db->update('teachers',$data);
}
EDIT: This is my function that gets the data from the database
function get_unused_accounts($usersid)
{
$this->db->select('unused_accounts');
$this->db->from('teachers');
$this->db->where('user_id', $usersid);
$query = $this->db->get();
return $query->result();
}
I'm not sure if this puts out data in INT form. When I was using this to check if the user has at least one account, it always accepts as true even if the user has zero accounts.
I would suggest using raw SQL in your model for this purpose:
function add_accounts($uid, $quantity = 1)
{
$this->db->query('
UPDATE teachers
SET unused_accounts=unused_accounts+'.$quantity.'
WHERE user_id='.$uid
);
}
Now you can increment unused_accounts value by one for a user using
$this->teacher_data_model->add_accounts($user_id);
or by any amount you want using
$this->teacher_data_model->add_accounts($user_id, $amount);
Not sure if CodeIgniter's ActiveRecord would accept statement unused_accounts=unused_accounts+'.$quantity.', but if it does, you can try using this in your controller it wont work, see below for an edited part:
$data = array(
'user_id' => $user_id,
'unused_accounts' => 'unused_accounts + '.$amount
);
EDIT: Looks like if you want to use ActiveRecord, you must use $this->db->set() with a third parameter set to FALSE, so something like this in your model:
function add_accounts($unused_accounts, $uid, $amount = 1)
{
$this->db->where('user_id', $uid);
$this->db->set('unused_accounts', 'unused_accounts+'.$amount, FALSE);
$this->db->update('teachers');
}
Cant answer comments yet but
if($remaining_accounts = 1)
Will allways be true, try:
if($remaining_accounts == 1)
See PHP manual for comparison operators

Categories