Symfony Doctrine Group By - mysql

I need to get result from my database as associative array. I have gardens and families that related to this gardens as (One to Many). So for each garden i need to get array of families. So garden must be key, and array of families - it is a values. So i tried:
public function getFamiliesInGardens($client)
{
$qb = $this->createQueryBuilder('g');
$qb
->select(['g.name as garden', 'family.name', 'family.id'])
->join('g.growing', 'growing')
->join('growing.plant', 'plant')
->join('plant.family', 'family')
->where('g.client = :client')
->orderBy('g.name')
->addOrderBy('growing.endDate', 'DESC')
->setParameter('client', $client);
$grow = $qb->getQuery()->getArrayResult();
return $grow;
}
I got:
[0] => array(3) {
["garden"]=> string(1) "1"
["name"]=>string(9) "Brassicas"
["id"]=> int(13)
}
[1] =>
array(3) {
["garden"]=> string(1) "1"
["name"]=> string(13) "Miscellaneous"
["id"]=> int(18)
}
But i expect:
[0] => array(1) {
["1"] => array(2) {
[0] => array(2) {
["name"] =>string(9) "Brassicas"
["id"] => int(13)
},
[1] => array(2) {
["name"]=>string(9) "Miscellaneous"
["id"]=> int(18)
},
}
}
If i will add group by garden, result will be the same as first, but garden will be chosed once without repeat. Same for family. So, what can i change to get array: garden => families?

I came across this use case 3 years ago where I hoped the same. However, GROUP BY does not work that way.
You would have to manually iterate over the records and group them as you require. For example, something like this:
$gardens = ....
$groups = [];
for ( $gardens as $g ){
if (!array_key_exists($g['id'], $groups)){
$groups[$g['id']] = [];
}
$groups[$g['id']][] = $g;
}

Related

Comma separated Output in yii2

In the user table I have mobileno column for every user. And in the auth_assignment table I haveauthoriations. I want all mobile no of all the users who has autthoriation 'c_apo'. The output I want is only - 7777777777,9999999999.
The query I'm using is -
$mobiletemp = User::find()->leftJoin('auth_assignment', 'auth_assignment.user_id = user.id')->select('mobileno')->andWhere(['auth_assignment.item_name' => 'c_apo'])->asArray()->all();
$mobile = ArrayHelper::getColumn($mobiletemp, 'mobileno');
var_dump($mobile);
The output I'm getting is -
array(1) { [0]=> array(2) { [0]=> string(10) "9999999999" [1]=> string(10) "7777777777" } }
$mobile = User::find()
->select('mobileno')
->leftJoin('auth_assignment', 'auth_assignment.user_id = user.id')
->andWhere(['auth_assignment.item_name' => 'c_apo'])
->column();
$mobile = implode(",", $mobile);
//Here is a possible solution
public $exitingMember;//have to declare virtual field in model
$alreadyMember = TaskCrewEmployee::find()
->select('GROUP_CONCAT(tce_u_id) as exitingMember')
->where(['tce_ts_id'=>500])
->groupBy(['tce_ts_id'])
->one();

JSON Summarize for Dashing List

I am creating a Dashing job that pulls down some data from an API (this runs Ruby)
SCHEDULER.every '15m', :first_in => 0 do |job|
url = "https://blah.com
response = RestClient.get(url, {:Authorization => 'blahblah'})
current_timelist = JSON.parse(response)
acctitems = current_timelist.map do |row|
row = {
:label => row['member']['name'],
:value => row['actualHours']
}
end
# Update the List widget
send_event('timelist', { items: acctitems } )
end
I want to summarize based on the member name, but it lists every entry.
The JSON that is received from the API looks as follows (I have shortened this, and changed the names only), note the actualHours can be 0:
[
{
"member": {
"name": "User 1"
},
"actualHours": 0.2
},
{
"member": {
"name": "User 2"
},
"actualHours": 1.5
},
{
"member": {
"name": "User 2"
},
"actualHours": 0.17
}
]
I would also like to sort this so that I can have the top member at the top ect. I would also like to send a second event with the top person in the list (so they can get a gold star).
As I understood from your question, you need something like this aggregation
out = h.reduce({}) do |result, item|
key = item[:member][:name]
if result[key].nil?
result[key] = [item[:actualHours]]
else
result[key].push(item[:actualHours])
end
result
end
it will return the following output
{"User 1"=>[0.2], "User 2"=>[1.5, 0.17]}
You can iterate over it and filter what you need.
Thanks to #Stanislav for his code as that formed the basis of the fix I managed to get working.
SCHEDULER.every '15m', :first_in => 0 do |job|
url = "website.com"
response = RestClient.get(url, {:Authorization => 'BlahBlah'})
current_timelist = JSON.parse(response)
time = {}
acctitems = current_timelist.map do |row|
key = row['member']['name']
value = row['actualHours']
if time[key].nil?
time[key] = [value]
else
time[key].push(value)
end
end
resulttime = time.map do |result|
result = {
:label => result[0],
:value => result[1].inject(:+)
}
end
# Update the List widget
send_event('timelist', { items: resulttime })
end

Perl, checking various types of hash for empty key values, json

I'm implementing right now some kind of mock for my function. And i have a little problem here. Depending on situation, i could get different kind of json as well as a different kind of hash of it. It can be a simple hash with empty values of keys or hash of array of hashes with empty or not empty values.
my %ch1 = (
"a" => "",
"b" => "",
"c" => ""
);
my %ch2 = (
"tab" => [
{
"a" => 11,
"b" => 22,
"c" => 33
},
{
"a" => 44,
"b" => 55,
"c" => 66
}
]
);
I need to make a function that checks both types of hash, counts empty values and compares with ammount of keys of hash.
This one kinda works for the first hash, but i don't know how to make it work for both hashes without hardcoding.
my $tck = 0;
for (keys %ch1){
if ($ch1{$_} eq ""){
print "'$ch1{$_}'\n";
$tck++;
}
}
if ($tck == scalar keys %ch1){
# do something
}
Any suggestions?
You could use Data::Visitor::Callback to do that. It's a pretty straight-forward implementation, as long as there are no other things that contain empty strings in your data structure.
The module visits each item in a data structure and calls user-defined callbacks on those items. It will do that for every ref and every value in those refs.
use strict;
use warnings;
use Data::Visitor::Callback;
my %ch1 = (
"a" => "",
"b" => "",
"c" => ""
);
my $empty_strings;
my $v = Data::Visitor::Callback->new(
value => sub {
++$empty_strings if $_ eq q{}; # q{} is like '' but easier to read
},
);
$v->visit( \%ch1 );
print $empty_strings;
This will output 3, as there are three empty strings in the input hash. Note that it wants a hash reference, not the hash itself.
You can just as well pass in a more complex data structure. The layout does not really matter. I've added an empty string to your second example to show that it works.
use strict;
use warnings;
use Data::Visitor::Callback;
my $empty_strings;
my $v = Data::Visitor::Callback->new(
value => sub {
++$empty_strings if $_ eq q{};
},
);
my %ch2 = (
"tab" => [
{
"a" => 11,
"b" => 22,
"c" => 33
},
{
"a" => '',
"b" => 55,
"c" => 66
}
]
);
$v->visit( \%ch2 );
print $empty_strings;
In this case, the output is 1.
Because there is no easy way to distinguish if a value it looks at is a key or a value, the following things would also be counted with this implementation. So it's not perfect, but should work for the type of data you showed.
my %fail = (
"" => "foo", # one
"b" => [ "", "" ], # two, three
);
This data structure would yield a $empty_strings count of 3.
I am not confident that I understand the problem correctly, but assuming those are the only two types of data structures your program needs to be able to handle, here is one way of doing something with them:
#!/usr/bin/env perl
use strict;
use warnings;
use List::MoreUtils qw( all none );
my %ch1 = (
"a" => "",
"b" => "",
"c" => ""
);
my %ch2 = (
"tab" => [
{
"a" => 11,
"b" => 22,
"c" => 33
},
{
"a" => 44,
"b" => 55,
"c" => 66
}
]
);
use YAML::XS;
for my $h ( \(%ch1, %ch2) ) {
print Dump n_keys_empty_values( $h );
}
sub n_keys_empty_values {
my $h = shift;
if ( all { ref } values %$h ) {
return [ map { my $v = $_; map count_empty_values( $_ ), #$v } values %$h ]
}
elsif ( none { ref } values %$h ){
return [ count_empty_values( $h ) ];
}
else {
die "Unexpected data structure\n";
}
}
sub count_empty_values {
my $h = shift;
[ scalar keys %$h, scalar grep $_ eq '', values %$h ];
}
Output:
---
- - 3
- 3
---
- - 3
- 0
- - 3
- 0
The return value of n_keys_empty_values is a reference to an array of array references. The size of the outer array corresponds to the number of inner hashes passed. count_empty_values takes a reference to a hash and counts the number of keys and number of values which are empty strings.
Write your function in that way, that it iterates over the argument list. Then you can pass either a single hash \%ch1 or a list of hashes #{$ch2{tab}} to the function.
#! /usr/bin/perl
use strict;
use warnings;
my %ch1 = (
"a" => "",
"b" => "",
"c" => ""
);
my %ch2 = (
"tab" => [
{
"a" => 11,
"b" => 22,
"c" => 33
},
{
"a" => 44,
"b" => 55,
"c" => 66
}
]
);
my %ch3 = (
"tab" => [
{
"a" => '',
"b" => '',
"c" => ''
},
{
"a" => '',
"b" => '',
"c" => ''
}
]
);
sub fun
{
for (#_) {
my %ch = %{$_};
my $tck = 0;
for (keys %ch){
if ($ch{$_} eq ""){
print "'$ch{$_}'\n";
$tck++;
}
}
if ($tck == scalar keys %ch){
print "do something\n";
}
}
}
fun (\%ch1);
fun (#{$ch2{tab}});
fun (#{$ch3{tab}});

Symfony3 Forms–obtain Form with choices, default data etc. as JSON

I have a Symfony3 Application setup and would like to rebuild the frontend based on React now.
One of the Entities is User and each of them can have one or more Groups so in the HTML form a list of Checkboxes appears, so the admin can select the groups attached to a User.
In UserType.php this looks like that:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', TextType::class)
->add('password', TextType::class)
->add('email', EmailType::class)
->add('groups', EntityType::class, [
'class' => Group::class,
'choice_label' => 'name',
'expanded' => true,
'multiple' => true//,
//'data' => $builder->getData()->getGroups()
]);
}
To render the Form using React, it would be extremely handy to get a JSON response which could look like that:
{
"user": {
…
"groups": [<gid 1>, …]
"groups_available": [
{
"id": <gid 1>,
"name": …
},
…
]
}
}
So that the groups array contains all the ids of the groups, the user is attached to and groups_available a list of all available groups.
Right now I am using FOSRestBundle and in the Controller it looks like that:
public function getUserformAction($id=null)
{
//if the id is null, create a new user
//else get the existing one
…
$form = $this->createForm(UserType::class, $user);
$view = $form->createView();
return $this->handleView($view);
}
How can I do that?
you should try the following code:
->add('groups', EntityType::class, array(
//if Group is in AppBundle or use the required Bundle name
'class' => 'AppBundle:Group',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.name', 'ASC')
},
'choice_label' => 'name',
'multiple' => true,
'expanded' => true,
));
You can also get a reference from here
After digging in the source and with the help of the debugger I could manage to do it in a more less robust and generic way like so:
protected function getFormStructure(Form $form)
{
return $this->iterateFormview($form->createView(), []);
}
private function iterateFormview(FormView $view, array $result)
{
foreach($view as $child) {
$vars = $child->vars;
$data = ['value' => $vars['value']];
if(isset($vars['choices'])) {
$data['choices'] = [];
foreach ($vars['choices'] as $choice) {
array_push($data['choices'], [
'label' => $choice->label,
'value' => $choice->value]);
}
}
$result[$vars['full_name']] = $data;
if(count($child) > 0) {
$result = $this->iterateFormview($child, $result);
}
}
return $result;
}
Result (as json):
{
…
"user[groups]":
{
"value": "",
"choices": [
{
"value": 100,
"label": "the name"
},
…
]
}
}
I guess this routine needs to be extended if I need to support more types… But for now this will do it.

how to find the union of an unknown number of resultsets in DBIC?

Hi I am using the Helper::ResultSet::SetOperations libraries to find the union and intersection of some resultsets. If I know the number of the resultsets then things work fine, however I'm trying to get it to work for an unknown number of resultsets.
The following works when processing 3 'devices'
my $firstdevice = shift #{$devices};
my $rs1 = $self->search({ 'devices.devicename' => $firstdevice }, { join => { devicetype => 'devices' }, result_class => 'DBIx::Class::ResultClass::HashRefInflator' } );
my $seconddevice = shift #{$devices};
my $rs2 = $self->search({ 'devices.devicename' => $seconddevice }, { join => { devicetype => 'devices' },result_class => 'DBIx::Class::ResultClass::HashRefInflator' } );
my $thirddevice= shift #{$devices};
my $rs3 = $self->search({ 'devices.devicename' => $thirddevice }, { join => { devicetype => 'devices' },result_class => 'DBIx::Class::ResultClass::HashRefInflator' } );
my $data = [$rs1->union([$rs2, $rs3])->all];
However if I try to handle it for an unknown amount like below, I'm getting
Can't call method "result_class" on unblessed reference at /usr/local/share/perl/5.18.2/DBIx/Class/Helper/ResultSet/SetOperations.pm line 63.
when I run:
my $data = [$rs1->union([#rslist])->all];
Below is my attempt at getting it to work:
#shift off the first device as we still need $rs1
my $firstdevice = shift #{$devices};
my $rs1 = $self->search({ 'devices.devicename' => $firstdevice }, { join => { devicetype => 'devices' }, result_class => 'DBIx::Class::ResultClass::HashRefInflator' } );
my #rslist;
for my $device (#{$devices}) {
push #rslist, $self->search({ 'devices.devicename' => $device }, { join => { devicetype => 'devices' }, result_class => 'DBIx::Class::ResultClass::HashRefInflator' } );
}
my $data = [$rs1->union([#rslist])->all];
When you're pushing the return values of ->search to #rslist that's list context so search doesn't return a resultset but a list of the result objects which are hashrefs because of the HRI result_class.
Using search_rs instead will fix your issue.
As union takes an arrayref of resultsets I'd pass \#rslist instead of constructing a new arrayref.