Laravel reverse a collection hierarchy - php

Say I have a collection that looks like this:
$subscriptions = collect([
[
"id" => 1,
"event" => "FormCompleted",
"subscriber" => [
"id" => 2929,
"name" => "Adam",
"email" => "adam#dude.com"
]
],
[
"id" => 3,
"event" => "FormCompleted",
"subscriber" => [
"id" => 1928,
"name" => "Pope",
"email" => "pope#dude.com"
],
],
[
"id" => 4,
"event" => "StatusChanged",
"subscriber" => [
"id" => 2929,
"name" => "Adam",
"email" => "adam#dude.com"
]
]
]);
This shows a list of events with its subscriber. What I want is to re-group this to show a list of subscribers with its events. How do I group these results to get a result like this?
[
[
"id" => 2929,
"name" => "Adam",
"email" => "adam#dude.com",
"subscriptions" => [
[
"id" => 1,
"event" => "FormCompleted"
],
[
"id" => 4,
"event" => "StatusChanged"
],
]
],
[
"id" => 1928,
"name" => "Pope",
"email" => "pope#dude.com",
"subscriptions" => [
[
"id" => 3,
"event" => "FormCompleted"
]
]
]
]
Here is my code... which works, but it is very messy and I feel like there is a better way to do it...
$subscribers = $subscriptions->groupBy('subscriber.id')
->map(function($group) {
$subscriber = $group[0]->subscriber;
$subscriber['subscriptions'] = $group->map(function($subscription) {
unset($subscription['subscriber']);
return $subscription;
});
return $subscriber;
})->values();

I think like that this should return you all subscribers who have groups, so guarantees return not empty subscribers with events
More details you can read this in documention
return Subscriber::has('groups')->get()->groupBy('id');

Related

search for a value array in array in php

In my program i have arrays in the following format . I need to find whether a value is present in an the array
return [
"affiliates" => [
"name" => 'Affiliates',
"value" => 11
],
"business" => [
"name" => 'Business',
"value" => 12
],
"inquiries" => [
"name" => 'Inquiries',
"value" => 13
],
"students" => [
"name" => 'Students',
"value" => 14
],
"teachers" => [
"name" => 'Teachers',
"value" => 15
],
"Personal" => [
"name" => 'Personal',
"value" => 3
],
];
I am doing the following. I am expecting that the search will find the value(12) which is a business, but It is returning false.
$searchcategoryid = '12';
$key = array_search($searchcategoryid, array_column(config('peopletypes.students'), 'value'));
Please note that config('peopletypes.students')will return the array above mentioned. I am using laravel.
You have some sort of configuration problem, this code prints 1.
<?php
$searchcategoryid = '12';
$key = array_search($searchcategoryid, array_column([
"affiliates" => [
"name" => 'Affiliates',
"value" => 11
],
"business" => [
"name" => 'Business',
"value" => 12
],
"inquiries" => [
"name" => 'Inquiries',
"value" => 13
],
"students" => [
"name" => 'Students',
"value" => 14
],
"teachers" => [
"name" => 'Teachers',
"value" => 15
],
"Personal" => [
"name" => 'Personal',
"value" => 3
],
], 'value'));
echo $key;
Try to make sure that your config function actually returns the array you claim it to.

How to create an array tree based on path-style values?

I have a problem with multidimensional data arrays. I have a data array like this:
[
[
"name" => "netSnmp",
"oid" => "1.3.6.1.4.1.8072"
"status" => "current"
], [
"name" => "netSnmpObjects",
"oid" => "1.3.6.1.4.1.8072.1"
], [
"name" => "netSnmpEnumerations",
"oid" => "1.3.6.1.4.1.8072.3"
], [
"name" => "netSnmpModuleIDs",
"oid" => "1.3.6.1.4.1.8072.3.1"
], [
"name" => "netSnmpAgentOIDs",
"oid" => "1.3.6.1.4.1.8072.3.2"
], [
"name" => "netSnmpDomains",
"oid" => "1.3.6.1.4.1.8072.3.3"
], [
"name" => "netSnmpNotificationPrefix",
"oid" => "1.3.6.1.4.1.8072.4"
], [
"name" => "netSnmpNotifications",
"oid" => "1.3.6.1.4.1.8072.4.0"
], [
"name" => "netSnmpNotificationObjects",
"oid" => "1.3.6.1.4.1.8072.4.1"
]
]
I am looking for a simple way to create an array tree, based on the oid value from the array above. Those oid values are a dot-separated path. The more parts, the deeper in the final tree the corresponding item should be put.
The desired output:
[
"text" => "netSnmp",
"oid" => "1.3.6.1.4.1.8072",
"nodes" => [
[
"oid" => "1.3.6.1.4.1.8072.1",
"text" => "netSnmpObjects"
], [
"oid" => "1.3.6.1.4.1.8072.3",
"text" => "netSnmpEnumerations",
"nodes" => [
[
"text" => "netSnmpModuleIDs",
"oid" => "1.3.6.1.4.1.8072.3.1"
], [
"text" => "netSnmpAgentOIDs",
"oid" => "1.3.6.1.4.1.8072.3.2"
], [
"text" => "netSnmpDomains",
"oid" => "1.3.6.1.4.1.8072.3.3"
]
]
], [
"oid" => "1.3.6.1.4.1.8072.4",
"text" => "netSnmpNotificationPrefix"
"nodes" => [
[
"text" => "netSnmpNotifications",
"oid" => "1.3.6.1.4.1.8072.4.0"
], [
"text" => "netSnmpNotificationObjects",
"oid" => "1.3.6.1.4.1.8072.4.1"
]
]
]
]
]
Any idea how I can solve it?
You can key your data by oid in a new associated array: that way you can look up a certain parent key in a fast way.
Then it is just a matter of getting the parent key of a any given key (chopping off the final dot-separated part) and see where you have it in your new associated array, and then appending it to its nodes array.
Here is a function that does that:
function makeTree($arr) {
$keyed = [];
foreach ($arr as $item) $keyed[$item["oid"]] = $item;
$root = null;
foreach ($keyed as &$item) {
$key = $item["oid"];
$parent = substr($key, 0, strrpos($key, "."));
if (isset($keyed[$parent])) {
$keyed[$parent]["nodes"][] =& $item;
} else {
$root = $key;
}
}
return $keyed[$root];
}
You can run it like this on your sample data:
$arr = [
[
"name" => "netSnmp",
"oid" => "1.3.6.1.4.1.8072",
"status" => "current"
], [
"name" => "netSnmpObjects",
"oid" => "1.3.6.1.4.1.8072.1"
], [
"name" => "netSnmpEnumerations",
"oid" => "1.3.6.1.4.1.8072.3"
], [
"name" => "netSnmpModuleIDs",
"oid" => "1.3.6.1.4.1.8072.3.1"
], [
"name" => "netSnmpAgentOIDs",
"oid" => "1.3.6.1.4.1.8072.3.2"
], [
"name" => "netSnmpDomains",
"oid" => "1.3.6.1.4.1.8072.3.3"
], [
"name" => "netSnmpNotificationPrefix",
"oid" => "1.3.6.1.4.1.8072.4"
], [
"name" => "netSnmpNotifications",
"oid" => "1.3.6.1.4.1.8072.4.0"
], [
"name" => "netSnmpNotificationObjects",
"oid" => "1.3.6.1.4.1.8072.4.1"
]
];
$result = makeTree($arr);
print_r($result);

How to use $in in array of embed array mongodb

I have photos_comments collection:
{
"_id" : ObjectId(""),
"photo_id" : ObjectId(""),
"content" : "Comment 1",
"is_approved" : "1",
"user" : {
"user_id" : ObjectId(""),
"name" : "",
"avatar" : ".jpg"
},
"likes" : [
{
"user_id" : ObjectId("")
}
],
"like_count" : 1,
"reply_count" : 5,
"replies" : [
{
"reply_id" : ObjectId(""),
"content" : "Reply 1",
"is_approved" : "1",
"user" : {
"user_id" : ObjectId(""),
"name" : "",
"avatar" : ".jpg"
},
"likes" : [
{
"user_id" : ObjectId("")
}
],
"like_count" : 1
},
]
}
I use $in to check if current user like reply comment:
$collection->aggregate(
[
[
'$match' => [
'_id' => new ObjectId($comment_id)
]
],
[
'$project' => [
'replies.reply_id' => 1,
'replies.like_count' => 1,
'replies.content' => 1,
'replies.is_liked' => ['$in' => [['user_id' => $user_id], '$replies.likes']],
'replies.user' => 1,
'replies.created_at' => 1
]
],
['$sort' => ["replies.reply_id" => 1]],
['$limit' => 5]
]);
But replies.is_liked alway return false, although it exist user_id in likes array from replies array embed.
How to fix it? Thanks!
It looks like your post is mostly code; please add some more details.
If you want to alter the array content to add a new field based on a condition, then you want the $map operator, and probably using $addFields if you don't want to restrict or change the rest of the document returned:
$collection->aggregate([
[ '$match' => [
'_id' => new ObjectId($comment_id)
]],
[ '$addFields' => [
'replies' => [
'$map' => [
'input' => '$replies',
'in' => [
'reply_id' => '$$this.reply_id',
'content' => '$$this.content',
'is_approved' => '$$this.is_approved',
'is_liked' => [ '$in' => [ $user_id, '$$this.likes.user_id' ] ],
'like_count' => '$$this.like_count'
]
]
]
]],
... # any other pipeline
])
Or using $mergeObjects if your MongoDB supports it and you prefer:
$collection->aggregate([
[ '$match' => [
'_id' => new ObjectId($comment_id)
]],
[ '$addFields' => [
'replies' => [
'$map' => [
'input' => '$replies',
'in' => [
'$mergeObjects' => [
'$$this',
[ 'is_liked' => [ '$in' => [ $user_id, '$$this.likes.user_id' ] ] ]
]
]
]
]
]],
... # any other pipeline
])
In both cases of course where $user_id is your PHP variable as the singular value in argument to $in, and where the '$$this.likes.user_id' is the MongoDB representation of the array of user_id values in that inner array. Note the array is the second argument and the singular is the first.
The $map operator uses the '$$this' to represent the current element of the array being processed. In both examples this allows re-mapping of the array content, just as the operator name implies.

Removed array grouped key

Is it possible to remove the key after data is grouped? Now I'm working with the csv file import function. I have two rows of data with the same student but different books because I want to group the books based on the student ID.
Code
foreach ($book as $item) {
$item['books'] = [
'number' => $item['number'],
'description' => $item['description'],
];
if (!isset($group_by[$item['student_id']])) {
$group_by[$item['student_id']] = array(
'student_id' => $item['student_id'],
'name' => $item['name'],
);
}
$group_by[$item['student_id']]['books'][] = $item['books'];
}
This is my grouping function, it worked perfectly as expected but the data structure is not matched to my system
Result is here
array:1 [
"ST001" => array:9 [
"student_id" => "ST001"
"name" => "joe"
"books" => array:2 [
0 => array:2 [
"number" => "1"
"description" => "The magic"
]
1 => array:2 [
"number" => "2"
"description" => "Forest in norway"
]
]
]
]
Expect result
array:9 [
"student_id" => "ST001"
"name" => "joe"
"books" => array:2 [
0 => array:2 [
"number" => "1"
"description" => "The magic"
]
1 => array:2 [
"number" => "2"
"description" => "Forest in norway"
]
]
]
I have no idea how to remove the St001 array. I did tried this $group_by[] = array( but the books data will be break out of data structure.
Assign the inner array to another array.
$array = $array['ST001'];
It will help out here
foreach($book as $item)
{
$item['books'] = ['number' => $item['number'], 'description' => $item['description'], ];
if (!isset($group_by[$item['student_id']]))
{
$group_by[$item['student_id']] = array(
'student_id' => $item['student_id'],
'name' => $item['name'],
);
}
$group_by[$item['student_id']]['books'][] = $item['books'];
}
// remove key and get only value as you want
print_r(array_values($group_by));

REST API SkypeBot suggested actions

Trying to make REST API skype bot but have a problem with a suggested actions message.
I prepare JSON with code like this:
$message = [
"type" => "message",
"from" => [
"id" => $clientid,
],
"conversation" => [
"id" => $chatid,
],
"recipient" => [
"id" => $chatid,
],
"text" => "Color",
"inputHint" => "expectingInput",
"suggestedActions" => [
"to" => [ $reptoid ],
"actions" => [
[
"type" => "imBack",
"title" => "Blue",
"value" => "Blue"
],
[
"type" => "imBack",
"title" => "Green",
"value" => "Green"
],
],
],
"replyToId" => $replyid
];
And after I send - I get in skype only text, wihout any buttons.
What I'm doing wring?
Based on the Channel Inspector, it seems that Suggested Actions in Skype are only available in the context of Cards.

Categories