Laravel Collections: Filter with two cloumns - php

So let's just begin with the question.
I have a database with following structure:
id
first_user_id
second_user_id
1
1
2
1
2
4
1
2
1
And let's say i have a variable with id=1
$id = 1
I find the needed records with this.
Model::where('status',1)
->where('first_user_id', $id)
->orWhere('second_user_id',$id)->get();
I want to get all of the ids that is not equals to the $id in some of the columns.
For exampe:
if first_user_id is equals to $id
return second_user_id column
if second_user_id is equals to $id
return first_user_id column
I want to done that with Laravel Collections if it is possible?
The result must be array with the ids from condition above.
Example output:
Array
(
[0] => 2 // second_user_id from first record
[1] => 2 // first_user_id from the last record.
)
For more clearly here is some pseudo php code for what i exactly want
<?php
$students = [
[
"first_user_id" => 1,
"second_user_id" => 2
],
[
"first_user_id" => 2,
"second_user_id" => 3
],
[
"first_user_id" => 1,
"second_user_id" => 3
],
[
"first_user_id" => 4,
"second_user_id" => 6
],
];
$var = 2; // Authenticated user
$arr = [];
foreach($students as $student) {
if($student['first_user_id'] == $var || $student['second_user_id'] == $var) {
if($student['first_user_id'] == $var) {
$arr[] = $student['second_user_id'];
} else $arr[] = $student['first_user_id'];
}
}
print_r($arr);
Output:
Array
(
[0] => 1
[1] => 3
)
Thank you.

I guess you can use union in that case
$first = DB::table('users')
->where('second_user_id',$id)
->select('first_user_id as user_id');
$users = DB::table('users')
->where('first_user_id',$id)
->select('second_user_id as user_id')
->union($first)
->get(['user_id']);
In SQL it would be like
select first_user_id as user_id from users where second_user_id = :id
union
select second_user_id as user_id from users where first_user_id = :id

Related

How do I get the position of an element in an array in php/laravel

So I have a
student model,
subject model,
marks model, which has the total score field
what I am trying to do is get the total score in an exam for each student in a class and then retrieve the results according to the highest score in the class and then position those scores as 1,2,3...
then finally get the position a single student and store it in an exam record table.
so far I was able to achieve getting the total score in an exam for each student, stored them in an array, sorted them according to the highest score,
the only issue now giving me a headache is getting the position of those scores from the array, my question is how can I get the position of a score for a student, or is there a way to add the positions to the scores and then retrieve the position for a student
For example
1 student_id => 2, total_score => 500
2 student_id => 3, total_score => 455
3 student_id => 5, total_score => 345
here is my code below, Please anyone with an idea how to solve this I need your help.
TextInput::make('position')->numeric(
function (Closure $set) {
// Get all students from class
$studentsInClass = $this->class->students;
//empty array to store student's total_score
$totalScore = [];
// loop through students get all their total_score on all subjects from mark table and sum it, then store it
in totalScore array.
foreach ($studentsInClass as $key => $student) {
$totalScore[] = array('student_id' => $student->id, 'total_score' => $student->marks->sum('total_score') );
}
// Sort scores from highest to lowest
$sortedScores= array_values(array_reverse(Arr::sort($totalScore, function ($value) {
return $value['total_score'];
})));
// get the current student Id
$id = $this->student->id;
// find a student in the array that matches the current student id and return his score.
//so this is where I would like to return the score and position of the student
$filteredArray = Arr::where($sortedScores, function ($value, $key) use ($id) {
return $value['student_id'] == $id;
});
}
)->disabled(),
if you dd($sortedScores)
You have a two-dimensional array.
$sortedScores = [
['student_id' => 2, 'total_score' => 443],
['student_id' => 4, 'total_score' => 410],
['student_id' => 1, 'total_score' => 371],
['student_id' => 3, 'total_score' => 170],
];
The index of each row is already consecutive from 0-3. I think you want to add a rank to the rows.
foreach($sortedScores as $idx => $row)
$sortedScores[$idx]['rank'] = $idx+1;
//test output
var_export($sortedScores);
Output:
array (
0 =>
array (
'student_id' => 2,
'total_score' => 443,
'rank' => 1,
),
1 =>
array (
'student_id' => 4,
'total_score' => 410,
'rank' => 2,
),
2 =>
array (
'student_id' => 1,
'total_score' => 371,
'rank' => 3,
),
3 =>
array (
'student_id' => 3,
'total_score' => 170,
'rank' => 4,
),
)
If you want rank to start at 0, just assign $idx.
Try on https://3v4l.org/9Dv7D
I hope this helps and that I understood your problem correctly.
To find the key for a specific value in a multidimensional array see 'PHP Multidimensional Array Searching (Find key by specific value)'
You can use the array_search() function. This will either return the key of the value you are looking for or false if it is not in the array.
$letters = ['a', 'b', 'c', 'd'];
$key = array_search('b', $letters);
//In this case $key will equal to 2.
Presuming that $filteredArray contains a single item, then the first key should be the student's position in the sorted array.
$position = array_keys($filteredArray)[0];

How I get data by group User ID for foreach controller function in Laravel

How can I get data by grouping user_id for a foreach loop in a controller's function in Laravel. For example, user_id = 2, 5 rows available, user_id = 1, 10 rows available. Then show 2 arrays.
$lists = lists::wherestatus(1)->groupby('user_id')->get();
foreach($lists as $list){
$list = functionHere;
}
What function can I create for this on the controller for grouping?
I need more information, but based on what you shared, you should be able to do this (removing the foreach):
$lists = Lists::whereStatus(1)->get()->groupBy('user_id');
The difference is that if you use groupBy before get, you are grouping your query by user_id, so instead of getting 5 rows for user_id = 2 and 10 for user_id = 1, you are going to get 2 rows and just the latest data, so you need to use Collection's groupBy.
What you want to do is group all the information by user_id but have each row, a schema like this:
[
'1' => [ // user_id
['user_id' => '1', 'column1' => 'random value'],
['user_id' => '1', 'column1' => 'other value'],
// 8 remaining rows
],
'2' => [ // user_id
['user_id' => '2', 'column1' => 'other nice value'],
// 4 remaining rows
],
]
you should first in List model set:
public function scopeStatus(){
return $this->where('status','1');
}
and in your controller:
$products = List::status()->groupby('user_id')->get();

Trying to merge two results of SQL queries - ToDoList App

I am trying to merge two results of two queries in MYSQL using PHP, but I am puzzled how to do it! I am using PDO. I am programming for a hobby and am trying to make a to do list app just like a Trello board. However, I just can't figure out how to merge two results from different tables in a database.
The idea is as follows:
I have a table called 'task_lists' with the content:
'list_id => 1, list_name = 'listOne'
'list_id => 2, list_name = 'listTwo'
And a table called 'tasks':
task_id => 1, list_id => 1, task_name => 'taskOfListOne', duration => 5, is_done => 1
task_id => 2, list_id => 1, task_name => 'anotherTaskOfListOne', duration => 5, is_done => 1
task_id => 3, list_id => 2, task_name => 'taskOfListTwo', duration => 10, is_done => 0
And I am trying to create an array that is merged between the two results as something like:
(I know this is a rough picture of how the array is supposed to look like)
$result = [array]
[list_id] = 1, [list_name] = 'listOne' =>
[array][list_id] = 1, ['task_name] = taskOfListOne,[duration] = 5, ['is_done'] => 1
[array][list_id] = 1, ['task_name] = anotherTaskOfListOne,[duration] = 5, ['is_done'] => 1
[list_id] = 2, [list_name] = 'listTwo' =>
[array][list_id] = 2, ['task_name] = taskOfListTwo,[duration] = 5, ['is_done'] => 1
Is this even possible? I have tried a Union sql query and methods like nested foreach statements, but none of them worked for me. Am I missing something here?
PS: Sorry for my bad english.
Have you tried a left join?
SELECT TL.`list_id`, TL.`list_name`, T.`task_name`, T.`duration`
FROM task_lists AS TL
LEFT JOIN tasks as T ON TL.`list_id` = T.`list_id`
And then in PHP you build the array in the format you want.
Later edit:
Simple PHP example to parse SQL data as you asked (to remove duplicated info):
<?php
// $mysql_rows -> here is your query result, fetched as associative array
$filtered_array = array();
foreach ($mysql_rows as $row){
// Initiate record if is not already initiated
if (!isset($filtered_array[ $row['list_id'] ])){
$filtered_array[ $row['list_id'] ] = array(
'list_id' => $row['list_id'],
'list_name' => $row['list_name'],
'tasks' => array()
);
}
// Add tasks
$filtered_array[ $row['list_id'] ]['tasks'][] = array(
'task_name' => $row['task_name'],
'duration' => $row['duration'],
'is_done ' => $row['is_done ']
);
}
// Optional: if you want to remove list_id from $filtered_array key names, uncomment the next line
// $filtered_array = array_values($filtered_array);
?>

Possible to break statement in foreach loop?

I have two tables (user,user_group). Where user table contains
------------+-------------+------------------+
| user_id | user_name | user_group(id) |
------------+-------------+------------------+
and user_group table contains
+-----------------+-------------------+
| user_group_id | user_group_name |
+-----------------+-------------------+
Now I try to join them without using JOIN query. To solve this problem I have used double foreach() loop, but no result returns. I can't use break statement. How can I get the desired result using a loop? The desired result would be:
+-----------+-------------+-------------------+
| user_id | user_name | user_group_name |
+-----------+-------------+-------------------+
What I have so far:
public function user_get_item()
{
$this->db->select('*');
$this->db->from('users');
$results=$this->db->get()->result_array();
$this->db->select('*');
$this->db->from('user_group');
$group_data=$this->db->get()->result_array();
foreach($results as $v_results)
{
foreach($group_data as $v_group_data)
{
if($v_results['user_group']==$v_group_data['user_group_id'])
{
$v_results['user_group']=$v_group_data['user_group_name'];
}
}
}
return $results;
}
I think what you are trying to do is changing the group id identifier by the group name in the current row if they match. So, replace:
$results['user_group']=$v_group_data['user_group_name'];
by:
$v_results['user_group']=$v_group_data['user_group_name'];
Anyway, what's wrong with joins? Making SQL queries will be always faster than a polynomic loop.
Presumably you would have this:
Array(
0 => Array(
[user_id] => 1,
[user_name] => John Doe,
[user_group] => 200
),
1 => Array(
[user_id] => 2,
[user_name] => Jane Doe,
[user_group] => 100
)
)
And:
Array(
0 => Array(
[user_group_id] => 100,
[user_group_name] => Admin
),
1 => Array(
[user_group_id] => 200,
[user_group_name] => Web User
)
)
So make a new array for the group so it looks like this (ID as key, Name as value):
Array(
[100] => Admin,
[200] => Web User
)
To do that:
public function getUserGroups()
{
$rows = array();
$this->db->select('*');
$this->db->from('user_group');
$group_data=$this->db->get()->result_array();
foreach($group_data as $results)
{
$rows[$results['user_group_id']] = $results['user_group_name'];
}
return $rows;
}
Then you just assign in the other method:
public function userGetItem()
{
# Get all the user groups
$groupData = $this->getUserGroups();
# Get your original user list
$this->db->select('*');
$this->db->from('users');
$results=$this->db->get()->result_array();
$row = array();
foreach($results as $users) {
$row[] = array(
'user_id' => $users['user_id'],
'user_name' => $users['user_name'],
# Here you assign the group name from the user groups array
'user_group_name' => $groupData[$users['user_group']]
);
}
return $row;
}
Anyway, I think JOIN would be faster/better, but this should get you the results you are looking for, though I have not tested it, it should be close.

How to attach different value for additional field in pivot table Laravel 5

I have project_group pivot table with this fields: id, group_id, project_id, admin_id, user_id
This I use to attach group and projects together:
$group -> projects() -> attach($projects,array('admin_id' => Auth::user()->id));
Is it possible to for every record in that pivot table add diffirent user_id.
For example:
First record:
id = 1, group_id = 1 project_id = 2 admin_id = 1 user_id = 1
Second record:
id = 2, group_id = 1 project_id = 3 admin_id = 1 user_id = 1
3th record:
id = 3, group_id = 1 project_id = 2 admin_id = 1 user_id = 2
4th record:
id = 3, group_id = 1 project_id = 3 admin_id = 1 user_id = 2
Basicly if I select 2 projects from projects html list and 2 users from html users list I need to get result like in example above...
Sure, like this:
$projects = [
2 => ['admin_id' => 1, 'user_id' => 1],
3 => ['admin_id' => 1, 'user_id' => 2],
// and so on
];
$group->projects()->attach($projects);
And if I understood your problem right, you can build such an array like this:
$projectsIds = [2,3];
$userIds = [1,2];
$projects = [];
$adminId = Auth::id();
foreach($userIds as $userId){
$projects += array_fill_keys($projectIds, [
'admin_id' => $adminId,
'user_id' => $userId
]);
}
$group->projects()->attach($projects);
Here is one solution, if someone has better way please put here...
$projectsIds = [11,33];
$userIds = [1,2,4];
$adminId = Auth::id();
if($group -> save()){
foreach($userIds as $userId){
$group -> projects() -> attach($projectsIds,array('admin_id' => $adminId, 'user_id' => $userId));
}

Categories