Laravel groupBy and pluck some values - php

I am using laravel 8.x and building rest API project.
I am stuck with a query.
I have a table
id
name
type
color
1
Dog
animal
black
2
Dog
animal
yellow
3
Cat
animal
red
4
Cat
animal
white
I want to do something like that,
$animals->groupBy('name')->get()
and hope to get result like,
$animals=[
{
name: "dog",
type: "animal",
colors: ["black", "yellow"]
},
{
name: "cat",
type: "animal",
colors: ["red", "white"]
}
]
Anyone help me?

I will slightly improve the Erik answer.
$animals = Animals::all()->groupBy('name')->map(function($item) {
return [
'name' => $item[0]['name'], // the name always the same
'type' => $item[0]['type'], // if the type not change (as the name)
'colors' => $item->pluck('color')->unique()->toArray(),
];
})->values()->toArray();

I would use Laravel mapToGroups collection method
$data = Animal::get();
$animals = collect($data)->mapToGroups(function ($item) {
return [$item['name'] => $item];
})->map(function ($itemGoup, $name) {
return [
'name' => $name,
'type' => data_get($itemGoup, '0.type'),
'colors' => collect($itemGoup)->pluck('color')->unique()->values()->toArray(),
];
})->values()->toArray();
with output:
[
{
"name": "Dog",
"type": "animal",
"colors": ["black", "yellow"]
},
{
"name": "Cat",
"type": "animal",
"colors": ["red", "white"]
}
]

Related

php arrange repeating items in an object

this object:
"permission_category": [{
"id": 2,
"name": "user",
"permissions": {
"id": 2,
"name": "userCreate"
}
},
{
"id": 2,
"name": "user",
"permissions": {
"id": 3,
"name": "userUpdate"
}
}
]
can i convert it to this?
"permission_category": [{
"id": 2,
"name": "user",
"permissions": [
{
"id": 2,
"name": "userCreate"
},
{
"id": 3,
"name": "userUpdate"
},
]
}
]
Do I have such a chance? Because if I return this with foreach it will print the same category name more than once. Is it possible to show both userCreate and userUpdate permissions belonging to the user category under one category? The object looks like this to me. I have created a relationship between 4 tables in Laravel. I will share their code with you too. Please tell me if what I need to do is change the code between relationships. Please tell me if what I need to do is to edit the array in the output with php array functions. I don't know anything about this, I need some help. Sorry for prolonging the topic. I'm sure there's a right and easy way to do this. Since I don't know, I had to ask. I would like to express my thanks and regards to those who have helped in advance.
Laravel Relationship:
UsersController.php
public function add() {
$data = array();
$user = AdminUsers::where('id', $this->uid())->first();
if($user->hasAdministrator()->first())
$data['permission_category'] = PermissionCategory::with('permissions')->get();
else
$data['permission_category'] = PermissionsResource::collection($user->permissions()->with('category')->get());
return $data;
die();
return view('admin.users.add', $data);
}
PermissionsResource.php
return [
"id" => $this->category[0]->id,
"name" => $this->category[0]->name,
"permissions" => [
"id" => $this->id,
"name" => $this->name
],
];
AdminUsers.php (Model)
public function permissions() {
return $this->belongsToMany(Permissions::class, 'admin_perms');
}
Permissions.php (Model)
public function category() {
return $this->belongsToMany(PermissionCategory::class, 'permissions', 'id');
}
admin_users table:
-id
-username
permission_category table:
-id
-name
permissions table:
-id
-permission_category_id
-name
admin_perms table:
-id
-admin_users_id foreign key
-permissions_id foreign key
do
$adminPermsWithCategory = AdminPerms::with('permission.category')
->where('admin_users_id', $user->id);->get();
return new AdminPermsResource($adminPermsWithCategory);
and in AdminPermsResource:
$data = [];
foreach ($this->resource as $item) {
if(!array_key_exists($item->permission->category->name, $data)){
$data[$item->permission->category->name] = [
"category_id" => $cat->id,
"category_name" => $cat->name,
];
}
$data[$item->permission->category->name]['permissions'][$item->permission->id] = new PermissionsResource($item->permission);
}
return $data;
and in PermissionsResource:
return [
"permission_id" => $this->id,
"permission_name" => $this->name,
];
maybe this help. I am writing without trying, sorry for the answer before.

How can I build an object/array?

I am rather new to PHP so I don't know how to work with these datasets. I make a MySQL select and get back an object like this:
{
"membername": "NAME",
"bookingdate": "2020-02-03",
"categoryid": 1,
"dailyworkhourssum": "7.70"
},
{
"membername": "NAME",
"bookingdate": "2020-02-03",
"categoryid": 3,
"dailyworkhourssum": "1.2"
},
{
"membername": "NAME",
"bookingdate": "2020-02-05",
"categoryid": 3,
"dailyworkhourssum": "7.70"
},
I want to iterate through this and in the end it should look like this:
{
"membername": "NAME",
"bookingdate": "2020-02-03",
"categoryid1": true,
"categorid3": true,
"dailyworkhourssum1": "7.70",
"dailyworkhourssum3": "1.2"
},
{
"membername": "NAME",
"bookingdate": "2020-02-05",
"categoryid": 3,
"dailyworkhourssum": "7.70"
},
What this does is that it merges tow fields together (if they have the same bookingdate )into one so that I can display it in a table without reoccurring dates.
My problem:
I don't know what this type of data is called.
I don't know how to create something like this.
I can add fields to this type of data with $data->newField = example so I think that this is an object.
In JS it's called an object, but in PHP you will use an associative array instead.
In your case, I think, you have an array of associative arrays. It looks like this:
$books = [
[
"membername" => "NAME",
"bookingdate" => "2020-02-03",
"categoryid" => 1,
"dailyworkhourssum" => "7.70"
],
[
"membername" => "NAME",
"bookingdate" => "2020-02-03",
"categoryid" => 3,
"dailyworkhourssum" => "1.2"
],
[
"membername" => "NAME",
"bookingdate" => "2020-02-05",
"categoryid" => 3,
"dailyworkhourssum" => "7.70"
]
];
If you wanna merge an arrays with the same "bookingdate" then I recommend you to loop through this array and add its elements to another associative array with bookingdates as keys, and check, in case if there is such key already, then merge the arrays, like this:
$merged = [];
foreach ($books as $book) {
$date = $book['bookingdate'];
if (isset($merged[$date])) {
$merged[$date] = $merged[$date] + $book;
} else {
$merged[$date] = $book;
}
}
I think that it is not a valid code (no time, sorry), but I hope, you cautch the idea.
If you want a 'list' instead of an associative array, than you can do this:
$mergedList = array_values($merged);
Thus you will rid of string keys.
If I understood correctly, you obtain a table with 4 columns an a variable number of rows and you want to transform it to a table with a variable number of columns. For that, using a data structure where every item is different from the previous one can make everything harder than it needs. I'd suggest you use a fixed structure:
// I'm assuming you have a PHP array as starting point
$input = [
[
'membername' => 'NAME',
'bookingdate' => '2020-02-03',
'categoryid' => 1,
'dailyworkhourssum' => '7.70',
],
[
'membername' => 'NAME',
'bookingdate' => '2020-02-03',
'categoryid' => 3,
'dailyworkhourssum' => '1.2',
],
[
'membername' => 'NAME',
'bookingdate' => '2020-02-05',
'categoryid' => 3,
'dailyworkhourssum' => '7.70',
],
];
$output = [];
foreach ($input as $data) {
// We'll group by booking date
if (!isset($output[$data['bookingdate']])) {
$output[$data['bookingdate']] = [
'membername' => $data['membername'],
'bookingdate' => $data['bookingdate'],
'categoryid' => $data['categoryid'],
'dailyworkhourssum' => [],
];
}
// A single date may have several daily work hours
$output[$data['bookingdate']]['dailyworkhourssum'][] = $data['dailyworkhourssum'];
}
// We discard array keys (we only needed them to group)
echo json_encode(array_values($output));
[{
"membername": "NAME",
"bookingdate": "2020-02-03",
"categoryid": 1,
"dailyworkhourssum": ["7.70", "1.2"]
}, {
"membername": "NAME",
"bookingdate": "2020-02-05",
"categoryid": 3,
"dailyworkhourssum": ["7.70"]
}]
Wherever you consume this JSON you just need to loop the dailyworkhourssum array. You may also want to loop the entire structure before printing the table and keep a counter in order to determine the maximum number of columns so you can draw empty cells where needed (tables are rectangular).

I need to know how to make associated array of country and city

i need to know how i can make a array from db tables. i want something like that. i have 3 tables in data base country - state - city
data base structure is as follow
countries-table:
| id | country |
|----|----------------|
| 1 | united kingdom |
states-table
| id | state |
|----|----------------------|
| 1 | united westyorkshite |
cities-table
| id | city |
|----|----------------------|
| 1 | united wakefield |
The expected result:
{
value: '12',
label: 'United Kingdom',
children: [
{
values: '34',
labels: 'West YorkShire',
children: [
{
value: '400',
label: 'Dewsbury'
},
{
value: '401',
label: 'Wakefield'
}
]
}
This is what I've tried:
$country_array = array();
$array = Country::select('countries.country', 'countries.country_id')
->isDefault()
->active()
->sorted()
->pluck('countries.country', 'countries.country_id')
->toArray();
// print_r($array);
foreach($array as $key => $arr) {
$array_state = State::select('states.state', 'states.state_id')
->where('states.country_id', '=', $key)
->isDefault()
->active()
->sorted()
->pluck('states.state', 'states.state_id')
->toArray();
foreach($array_state as $key_1 => $arr_1) {
$array_city = City::select('cities.city', 'cities.city_id')
->where('cities.state_id', '=', $key_1)
->active()
->sorted()
->pluck('cities.city', 'cities.city_id')
->toArray();
$array_state_1 [] = array (
'value' => $key_1,
'label' => $arr_1,
'children' => $array_city
);
}
$country_array [] = array (
'value' => $key,
'label' => $arr,
'children' => $array_state
);
}
dd($country_array);
I need these labels as well like value and label. i cant remove that as i am using vuejs element ui component.
I try to use normal foreach loop but its doing time out. any idea how i can do that in laravel using maps or collection or what is the best solution.
I am using php 7 and laravel version is 5.6
To retrieve all necessary data in a single statement, I would use nested with's. For example:
$result = Country::where('country_id', 12)
->with(['states' => function ($query) {
$query->where('state_id', 34);
$query->with('cities');
}])
->get();
The next step is to modify the data. The map() function is indeed very useful for this purpose, although the nesting makes it look a little complex:
$mapped = $result->map(function ($country, $key) {
return [
'value' => $country->country_id,
'label' => $country->country,
'children' => $country->states->map(function ($state, $key) {
return [
'value' => $state->state_id,
'label' => $state->state,
'children' => $state->cities->map(function ($city, $key) {
return [
'value' => $city->city_id,
'label' => $city->city,
];
}),
];
}),
];
});
Finally to display it, we convert the whole thing to a JSON array.
echo '<pre>' . $mapped->toJson(JSON_PRETTY_PRINT) . '</pre>';
Which gives me:
[
{
"value": 12,
"label": "United Kingdom",
"children": [
{
"value": 34,
"label": "West YorkShire",
"children": [
{
"value": 400,
"label": "Dewsbury"
},
{
"value": 401,
"label": "Wakefield"
}
]
}
]
}
]

How to select a field of a contained association as a field of the main entity?

I have Cakephp 3 in a project and I'm doing api rest to get a JSON to get data in mobile devices.
I have two tables in associated with a foreign key like this:
MySql tables
----------------------
Table Tickets:
|id|code|price_id|
Table Prices
|id|price|
----------------------
In TicketsTable CakePHP:
$this->belongsTo('Prices', [
'foreignKey' => 'price_id',
'joinType' => 'INNER'
]);
In controller when I make REST api:
$this->loadModel('Tickets');
$entradas = $this-> Tickets->find('all')
->contain('Prices')
->select(['Tickets.code','Prices.price'])
->limit('200')
->toArray();
Then this array, parsed to JSON return this:
"result":{
"tickets":[
{
"code":"08998112773",
"prices":{
"prices.price":1
}
},
{
"code":"07615265880",
"prices.prices":{ .........
And I want to return this JSON:
"result":{
"tickets":[
{
"code":"08998112773",
"price":1
},
{
"code":"07615265880",
"price":1 .........
That is, that prices do not insert into a new array and that the name of the table does not appear in the field name.
Thanks a lot!!!!
You could use use Cake\Collection\Collection::map() to create a new array:
$tickets = [
'result' => [
'tickets' => [
[
'code' => '123',
'prices' => [
'prices.price' => '2'
]
],
[
'code' => '312423',
'prices' => [
'prices.price' => '4'
]
]
]
]
];
$collection = new Collection($tickets['result']['tickets']);
$new = $collection->map(function ($value, $key) {
return [
'code' => $value['code'],
'price' => $value['prices']['prices.price']
];
});
$result = $new->toArray();
debug(json_encode(['result' => ['tickets' => $new]], JSON_PRETTY_PRINT));
die;
The output is:
{
"result": {
"tickets": [
{
"code": "123",
"price": "2"
},
{
"code": "312423",
"price": "4"
}
]
}
}

How to create json string given below

I am android developer and new in PHP. I don't know PHP very well. I create
<?php
header('Content-Type: application/json; charset=utf-8');
$mysqli = new mysqli ('localhost', 'mabhi', '9993', 'general');
//PROBLEM LANGUAGE ?????
if (function_exists('mysql_set_charset')) {
mysqli_set_charset($mysqli, 'utf8');
} else {
mysqli_query($mysqli, "SET NAMES 'utf8'");
}
// Check if album id is posted as GET parameter
$myq = $mysqli->query('SELECT * FROM Ages');
while ($myr = $myq->fetch_assoc()) {
$array["Questions"][] = (array(
'Question' => $myr['Question'],
'Answer' => $myr['option1'],
'Answer' => $myr['option2'],
'Answer' => $myr['option3'],
'Answer' => $myr['option4'],
'CorrectAnswer' => $myr['CorrectAnswer'],
));
}
echo json_encode($array, JSON_UNESCAPED_UNICODE);
?>
output:
{
"Questions": [
{
"Question": "sfsa sfd s sdf",
"Answer": "vvv",
"CorrectAnswer": null
},
{
"Question": "dsfgdsfgv dsf dfs",
"Answer": "vvvv vv",
"CorrectAnswer": null
}
]
}
But I would like json output in below format: Answer are displayed multiple times for each question. Please suggest me what changes in my code.
{
"Questions": [
{
"Question": "dfsfdsfgv dfsfsd dfs sf",
"CorrectAnswer": 3,
"Answers": [
{
"Answer": "vvvvvvv"
},
{
"Answer": "vvv"
},
{
"Answer": "vv"
},
{
"Answer": "v"
}
]
},
{
"Question": "dgdsgdsgdsgszdfvgfvds",
"CorrectAnswer": 0,
"Answers": [
{
"Answer": "Lee"
},
{
"Answer": "Wrangler"
},
{
"Answer": "Levi's"
},
{
"Answer": "Diesel"
}
]
}
]
}
As pointed by jereon, you are overwriting the value of Answer key. You need to create a separate array for the all the Answers together.
Change
$array["Questions"][] = (array(
'Question' => $myr['Question'],
'Answer' => $myr['option1'],
'Answer' => $myr['option2'],
'Answer' => $myr['option3'],
'Answer' => $myr['option4'],
'CorrectAnswer' => $myr['CorrectAnswer'],
));
to
$array["Questions"][] = (array(
'Question' => $myr['Question'],
'Answers' => array((object)array('Answer' => $myr['option1']),
(object)array('Answer' => $myr['option2']),
(object)array('Answer' => $myr['option3']),
(object)array('Answer' => $myr['option4'])),
'CorrectAnswer' => $myr['CorrectAnswer'],
));
You should not assign multiple array elements with the same identifier ("Answer") as they would just overwrite each other. I would suggest you to use a non-associative array for the Answers so that your target JSON would look like this:
{
"Questions": [
{
"Question": "dfsfdsfgv dfsfsd dfs sf",
"CorrectAnswer": 3,
"Answers": [
"vvvvvvv",
"vvv",
"vv",
"v"
]
},
{
"Question": "dgdsgdsgdsgszdfvgfvds",
"CorrectAnswer": 0,
"Answers": [
"Lee",
"Wrangler",
"Levi's",
"Diesel"
]
}
]
}
Therefore you would use the following PHP code for the loop:
$array = array();
while ($myr = $myq->fetch_assoc()) {
$array["Questions"][] = array(
'Question' => $myr['Question'],
'CorrectAnswer' => $myr['CorrectAnswer'],
'Answers' => array(
$myr['option1'],
$myr['option2'],
$myr['option3'],
$myr['option4'],
),
);
}
First thing you are doing wrong is you are overwriting the value of answer options so what will happen is when your 1st option will be overwritten by 2nd option, 2nd option with 3rd and 3rd option with 4th option. So you will have to create an array for answers and push every answer in that array and in the end assign this answer option array to answer. So your code should look like below
while ( $myr = $myq->fetch_assoc () ) {
$answers_array=new array();
$answer_option=new stdClass(); // Create a object to format in required format and use this object to store every option of answer
$answer_option->answer=$myr['option1'];
array_push($answers_array,$answer_option);
$answer_option->answer=$myr['option2'];
array_push($answers_array, $answer_option);
$answer_option->answer=$myr['option3'];
array_push($answers_array, $answer_option);
$answer_option->answer=$myr['option4'];
array_push($answers_array,$answer_option);
$array["Questions"][] = array(
'Question' => $myr['Question'],
'CorrectAnswer' => $myr['CorrectAnswer'],
'answers' => $answers_array;
);
}

Categories