how to get inner array from Outer array - php

I want to pull a array from outer array.
My result
I want to remove circle symbol of array
{
"Success": "1",
"Message": "Subtopic Wise Questions...",
"Subtopic Questions": [
[
{
"id": "93",
"topic_id": "36",
"name": "Cell membrane and organelle",
"created_at": "2018-08-29 23:06:34",
"updated_at": "2018-08-29 23:06:34",
"q_count": "127"
}
],
]
}
Here is my output result of array. the
My Controller code
foreach($findid as $v)
{
$count[] = DB::table('questions')
->join('subtopics', 'subtopics.id', 'questions.subtopic_id')
->select('subtopics.*', DB::raw('count(questions.id) as q_count'))
->where('subtopic_id', $v)
->get();
}
return response([
'Success' => "1",
'Message' => "Subtopic Wise Questions...",
'Subtopic Questions' => $count
]);

use first() to obtain just an object as per your image you want to remove extra array quotes so
$count[] = DB::table('questions')
->join('subtopics', 'subtopics.id', 'questions.subtopic_id')
->select('subtopics.*', DB::raw('count(questions.id) as q_count'))
->where('subtopic_id', $v)
->first();
Hope it helps you!

use whereIn method instead of where method
note only store id in array then used whereIn method
$count = DB::table('questions')
->join('subtopics', 'subtopics.id', 'questions.subtopic_id')
->select('subtopics.*', DB::raw('count(questions.id) as q_count'))
->whereIn('subtopic_id', array_wrap($findid))
->get();
note if not working as u want restult then add toArray() method in
query like this
$count->toArray();
return response([
'Success' => "1",
'Message' => "Subtopic Wise Questions...",
'Subtopic Questions' => $count
]);

Your query is expensive. Since you are looping through array of ids, you are going to run queries count(findid) number of times. You can optimize and achieve the same as,
$count = DB::table('questions')
->join('subtopics', 'subtopics.id', 'questions.subtopic_id')
->select('subtopics.*', DB::raw('count(questions.id) as q_count'))
->whereIn('subtopic_id', $findid)
->get();
return response([
'Success' => "1",
'Message' => "Subtopic Wise Questions...",
'Subtopic Questions' => $count
]);

Related

Laravel get sums from models with two and more joins

I want to get the sum of prices from contract table and sum of transactions together connected to user id. And how can i use where in this.
Table Contracts:
[
{
"id": 1,
"user_id":97,
"price":"100"
},
{
"id": 2,
"user_id":97,
"price":"200"
},
{
"id": 3,
"user_id":97,
"price":"300"
}
]
Table Transactions:
[
{
"id": 1,
"user_id":97,
"sum":"100"
},
{
"id": 2,
"user_id":97,
"sum":"200"
},
{
"id": 3,
"user_id":97,
"sum":"300"
}
]
My query:
$query = User::where([
['contracts_sum', '<', 'transactions_sum'],
])
->join('contracts', 'contracts.user_id', '=','users.id')
->join('transactions', 'users.id', '=','transactions.user_id')
->groupBy(['users.id'])
->select(
'users.id', 'users.name',
DB::raw('SUM(contracts.price) AS contracts_sum'),
DB::raw('SUM(transactions.sum) AS transactions_sum'),
)
->get();
But this variant returns sum multiplied to count of transactions table rows like this:
[
{
"id":97,
"name":"JOHN",
"contracts_sum":"1800",
"transactions_sum":"1800"
}
]
But i would like to get the data in this kind of form:
[
{
"id":97,
"name":"JOHN",
"contracts_sum":"600",
"transactions_sum":"600"
}
]
My advice would be to make use of laravel's relation feature, as it would make it a lot easier.
class User
{
public function transactions()
{
return $this->hasMany(Transaction::class, 'user_id', 'id');
}
public function contracts()
{
return $this->hasMany(Contract::class, 'user_id', 'id');
}
}
Then, in your controller, you could do the following:
$user = User::where('id', 97)
->withSum('contracts', 'price')
->withSum('transactions', 'sum')
->get();
return [
'id' => $user->id,
'name' => $user->name,
'contracts_sum' => $user->transactions_sum_sum,
'transactions_sum' => $user->contracts_sum_price
];
Not only does this look a lot cleaner, the query will be more efficient as well. More information on the aggregate functions can be found in the laravel documentation.

join two objects that have the same key into a collection php laravel

I am working with collections in Laravel and I have the following problem, I need to join objects that have the same key inside the array, at the same time obtain the total sum of one of its keys, this is a summary of my collection:
[
{
"cta_debe": 20,
"total": "2000.00",
},
{
"cta_debe": 22,
"total": "3600.00",
},
{
"cta_debe": 22,
"total": "1000.00",
},
{
"cta_haber": 10,
"total": "5000.00",
},
{
"cta_haber": 10,
"total": "4000.00",
}
]
where I have several objects that have the keys "cta_debe" and "cta_haber" with the same value, then I would like to join all the equal objects into one, in addition to adding the total column, this is an example of how I expect the collection to be :
[
{
"cta_debe": 20,
"total": "2000.00",
},
{
"cta_debe": 22,
"total": "4600.00",
},
{
"cta_haber": 10,
"total": "9000.00",
},
]
any idea how i could do this?
Preparing data as yours.
$data = collect([
collect(['cta_debe' => 20, 'total' => '2000.00']),
collect(['cta_debe' => 22, 'total' => '3600.00']),
collect(['cta_debe' => 22, 'total' => '1000.00']),
collect(['cta_haber' => 10, 'total' => '5000.00']),
collect(['cta_haber' => 10, 'total' => '4000.00']),
]);
Your solution start from here..
$collection = $data->groupBy(
fn ($item, $key) => $item->keys()->first()
)
->flatMap(function($groupValue, $groupKey){
return $groupValue->groupBy($groupKey)
->map(function($value, $key) use ($groupKey) {
return collect([
$groupKey => $key,
'total' => $value->map(
fn ($item) => (float) $item['total']
)->sum()
]);
});
})
// ->all(); // if you need array as output
->collect();
Output:
You can use collection methods:
$result = collect($myArray)->groupBy(function ($item) {
$keys = Arr::only($item, [ 'cta_debe', 'cta_haber' ]);
return count($keys) > 0 ? array_keys($keys)[0].'-'.$keys[0] : '';
})->filter(fn ($item, $key) => $key !== '')
->map(function ($group, $id) {
[ $key, $value ] = explode('-', $id);
return [
$key => $value,
'total' => collect($group)->sum('total')
];
});
What this does is: it groups by either cta_debe or cta_haber and creates groups that will be keyed by e.g. cta_debe-20 etc (this is in case there's items with the same identifier but different key). It then sums everything within the total of that group and returns that with the group name and identifier.
This is how I would probably do it.
Note: this solution assumes that the cta_* key is always the first key in the sub arrays.
Convert the whole array to collections and then use collection methods and Laravel helpers to get to the desired result.
$groupedData =
$arr
->groupBy(fn ($item, $key) => $item->keys()->first())
->flatMap(
fn($groupValue, $groupKey) =>
$groupValue
->groupBy($groupKey)
->map(
fn($value, $key) => [
$groupKey => $key,
'total' => $value->map(
fn ($item) => (float) $item['total']
)->sum()
]
)
);
dump($groupedData->all());
Collections docs
Helpers Docs
Laravel methods used:
flatMap()
groupBy()
map()
keys()
first()
sum()
This solution is based on #JSTECH 's solution, but it is converted to use Laravel collections and method chaining

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).

getting relational results from three tables into one nested array

i have googled for solution to my problem but nun helped me.
here i have three tables items, feeds and images. each item has one feed and one or more images.
i have 3 functions. one is to return records from items table the second one receives feeds_id (foreign key in items table) then return records from feeds table. the third function is to return all images related to items_id.
those functions are :
* To get all items in database:
function get_items(){
return $query = Database::getInstance('db')
->table('items')
->columns(
'id',
'items.rowid',
'items.feed_id as feed_id',
'title' )
->findAll();
}
* To get feed data from feeds table :
function get_feeds($id){
return $query = Database::getInstance('db')
->table('feeds')
->eq('id',$id)
->findAll();
}
* To get image data from images table :
function get_images($id){
return $query = Database::getInstance('db')
->table('images')
->columns('items_id','src as image_url',
'title as image_title',
'alt')
->eq('items_id',$id)
->findAll();
}
Then i have the following code to call those function and display the result in jsonformat:
$response['items'] = array();
$response['feeds'] = array();
$response['images'] = array();
foreach ($items = get_items() as $item) {
$response['items'][] = array(
'id' => (int)$item['rowid'],
'feed_id' => (int)$item['feed_id'],
'title' => $item['title'],
);
foreach ($feeds = get_feeds((int)$item['feed_id']) as $feed) {
$response['feeds'][] = array(
'title' => $feed['title'],
'logo_url' => $feed['logo_url'],
'site_url' => $feed['site_url'],
);
}
foreach ($images = get_images($item['id']) as $image) {
$response['images'][] = array(
'id' => $image['items_id'],
'url' => $image['image_url'],
'thumb' => $_SERVER['SERVER_NAME'] . /myServer/images/thumbs/'. 'thumb_'.basename($image['image_url']),
'title' => $image['image_title'],
'alt' => $image['alt']
);
}
}
echo json_encode($response, JSON_PRETTY_PRINT);
so, my expectation is to get json output like:
"items": [
{
"id": ,
"feed_id":
"title":
"feeds": [
{
"title": ,
"logo_url": ,
"site_url": "
}
]
"images": [
{
"id": ,
"url": ",
"thumb":
"title": "",
"alt": ""
},
{
....
}
]
}]
i mean each item array should include nested arrays of its related data coming from get_feeds and get_images functions.
instead of that, i get response like :
//here i select two items from my db
"items": [
{ //first_item
"id": ,
"feed_id":
"title":
},
{ //second_item
"id": ,
"feed_id":
"title":
}
],
"feeds": [
{ // feed data for first item
"title": ,
"logo_url": ,
"site_url": "
},
{ // feed data for second item
"title": ,
"logo_url": ,
"site_url": "
}
],
"images": [
{ // image data for first item
"id": ,
"url": ",
"thumb":
"title": "",
"alt": ""
},
{ // other images data
....
}
]
}]
as you see i am getting output without keeping relation between items, feeds and images, all of them are shown independently.
my queries are fine but i am suspecting error in my foreach statements.
i could fix this issue by joining those tree tables in one query, but i don't want to do that because i need to do validation and other operations to output comes from each table.
i appreciate your help
i found the solution. it is very easy :)
it is just like:
$response['items'][] = array(
'id' => (int)$item['rowid'],
'feed_id' => (int)$item['feed_id'],
'title' => $item['title'],
'feeds' => array(
)
'images' => array(
)
);

How do I remove nested object from an object in CakePHP?

CakePHP API returns result like this:
{
"status": "OK",
"themes": [
{
"Theme": {
"id": "20",
"user_id": "50",
"name": "dwdwdw",
"language_code_from": "cz",
"language_code_to": "en",
"type": "CUSTOM",
"created": "2014-10-19 15:36:05",
"count_of_cards": 0
}
}
]
}
I would like to ask, how can in remove nested Theme object to get result like this?:
{
"status": "OK",
"themes": [
{
"id": "20",
"user_id": "50",
"name": "dwdwdw",
"language_code_from": "cz",
"language_code_to": "en",
"type": "CUSTOM",
"created": "2014-10-19 15:36:05",
"count_of_cards": 0
}
]
}
Here is my CakePHP code:
$this->Theme->recursive = -1;
// GET USER ID
$themeData['user_id'] = $isSessionValid;
// GET ALL THEMES RELATED TO USER
$foundThemes = $this->Theme->find('all', array(
'conditions' => array(
'Theme.user_id' => $themeData['user_id'])
)
);
$themes = array();
// FOREACH THEMES AND GET COUNT FOR CARDS FOR EACH THEME
foreach($foundThemes as $foundTheme) {
// GET COUNT OF QUESTIONS FOR ACTUAL THEME
$countOfCards = $this->Theme->Card->find('count', array(
'conditions' => array(
'Card.theme_id' => $foundTheme['Theme']['id'])
)
);
// APPEND TO ACTUAL ARRAY
$foundTheme['Theme']['count_of_cards'] = $countOfCards;
array_push($themes,$foundTheme);
}
// SET SUCCESS RESPOSNSE
$this->set(array(
'status' => 'OK',
'themes' => $themes,
'_serialize' => array(
'status',
'themes',
)
));
Many thanks for any advice.
You can manipulate CakePHP's array formats using its built in Hash utility: http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash
What I would do would be to flatten the results:
$results = Hash::flatten($results);
Your data array will end up as a single dimensional array looking like this:
$results = array(
'status' => 'OK'
'themes.0.Theme.id' => 20,
...
'themes.1.Theme.id' => 21,
...
);
You can then use string replace to remove "Theme" from your keys:
$keys = array_keys($results);
$keys = str_replace('Theme.', '', $keys);
Then you can use Hash::expand to get your original array, now formatted how you want:
$results = Hash::expand(array_combine($keys, array_values($results)));
I dont think CakePHP supports this. if you want to do this with an easy way check the Set Utility.
http://book.cakephp.org/2.0/en/core-utility-libraries/set.html

Categories