I have created a new collection, when I try to add new values with a key in a foreach loop its not working. It only appends the 1st value. I want it to add all.
Here my code:
$new = new Collection();
foreach($messages as $message){
$new['message'] = $message->message;
}
But in the end instead of returning all messages, it only returns the 1st message:
{"message":"first"}
Instead it should have returned
{"message": "first", "message": "second"}
What is the problem?
Also when I do it without giving a key to a collection, it returns all:
foreach($messages as $message){
$new = $message->message;
}
You have an array with the same key, so the for loop overrides the same value again and again.
If you want a collection that contains objects with the same key you can change the following code to your need:
$new = array();
foreach ([1, 2, 3] as $i) {
$new[] = array('message' => $i);
}
$collection = collect($new);
Your making a collection with 1 key: namely "message" and then proceed to overwrite this key for the duration of your loop. PHP thus handles this as shown in your question: a collection with 1 key and 1 value.
This makes perfect sense (for example, how many houses are on your home address? Only one right? What would happen to your mail if there were 16 houses with the exact same address?).
What you want simply isn't possible: how should PHP know what it should return when you ask for the value at "message" if the entire data structure would consist out of the same key?
test this code :
$messages=['ali','reza','sara'];
$new = new Collection();
foreach($messages as $key=>$message){
$new->prepend($message,$key);
}
dd($new);
output :
Collection {#475 ▼
#items: array:3 [▼
2 => "sara"
1 => "reza"
0 => "ali"
]
}
Related
I have a array of array data which is came from database. And my "array to xml converter" can convert only one level array.
Basicly I want to convert my database table to xml file.
public function downloadXml()
{
$fields = ['created_at', 'updated_at'];
$products = Product::where('user_id', auth()->id())
->exclude($fields)->get()->toArray();// this is returnin array of array like [0 => [], 1 => []]
$products = array_collapse($products);
$result = ArrayToXml::convert($product, 'product');
}
The problem is array_collapse method trim the one level array but give me only last array not all arrays. How can I get all arrays? Any help appreciated..
Edit: when dd(Product::where('user_id', auth()->id())
->exclude($fields)->get()->toArray(););
Output1 = array:2 [▼ 0 => array:18 [▶] 1 => array:18 [▶] ]
When dd(array_collapse(Product::where('user_id', auth()->id())
->exclude($fields)->get()->toArray());)
Output2 = array:18 [▶]
I need something like output2 but the problem is output2 assuming there is only one product but actualy there is two product.
When performing a database query using Eloquent (Laravel ORM) the results are returned inside a Collection (one per row). This is the 'first level' array you are mentioning.
Unfortunately, a 'second level' array is needed to define the attributes (among others) for every row.
So you either have to:
extend your ArrayToXml converter to work with Laravel collections (i.e. print xml tag, loop through the elements and print the closing xml tag)
Split your xml converter into two pieces: a wrapper for the xml tag opening and closing and your current ArrayToXml::convert inside a map function.
Let me illustrate the latter:
public function downloadXml()
{
return Product::where('user_id', auth()->id())
->get()
->map(function (Product $product){
return ArrayToXml::convert($product->only('id', 'user_id'), 'product');
})
}
I have this piece of code as part of a foreach loop in my controller:
my $gr = My::Model::Group->new(id => $gra->gr_id);
$gra = My::Model::Group::Admin->new(id => $gra->id);
push(#$groups, {$gr => $gra});
In #$groups array I want to store anonymous hashes where the key element is the group object and the value element is the admin of that group object. Then in the template I want to show the list of different groups that the admin can log in, for that I have this code:
[%- FOREACH gr IN groups -%]
<li><input type="radio" name="group" value="[% gr.id %]">[% gr.name %]</input></li>
[%- END -%]
I know that the p IN partners is not right but is to show you what I want to achieve. Any suggestions on the template code?
duskwuff already explains in their answer that you can't use objects as hash keys as they get serialized and you'll lose the object-ness. My answer builds on that.
Let's say you have an array of arrays instead, where each inner array holds a pair of objects. I've created Moo classes to illustrate.
package My::Model::Group;
use Moo;
has [qw/id name/] => ( is => 'ro' );
package My::Model::Group::Admin;
use Moo;
has [qw/id name/] => ( is => 'ro' );
package main;
my $groups = [
[
My::Model::Group->new( id => 1, name => 'group1' ) =>
My::Model::Group::Admin->new( id => 1, name => 'foo' )
],
[
My::Model::Group->new( id => 2, name => 'group2' ) =>
My::Model::Group::Admin->new( id => 1, name => 'foo' )
],
[
My::Model::Group->new( id => 3, name => 'group3' ) =>
My::Model::Group::Admin->new( id => 1, name => 'bar' )
],
[
My::Model::Group->new( id => 4, name => 'group4' ) =>
My::Model::Group::Admin->new( id => 1, name => 'foo' )
],
];
There are four pairs. Two admins, four groups. Three of the groups belong to the foo admin, and one to bar. Now let's look at the template.
use Template;
my $tt = Template->new();
$tt->process( \*DATA, { groups => $groups }, \my $output )
or die $tt->error;
print $output;
__DATA__
[%- FOREACH item IN groups -%]
[%- DEFAULT by_admin.${item.1.name} = [] -%]
[%- by_admin.${item.1.name}.push(item.0) -%]
[%- END -%]
[%- FOREACH admin IN by_admin.keys.sort -%]
[%- FOREACH group IN by_admin.$admin -%]
[%- admin %] -> [% group.id %]
[%- END -%]
[%- END -%]
The relevant part obviously is the DATA section. We need to reorganize the array data structure into a hash that has the admins, and then each group sorted into one of the admin slots.
We don't need to create the by_admin variable. It will be created globally implicitly. But we do need to set a default value for $by_admin->{$item[0]->name} (I'm using Perl syntax now, to make it easier to understand). It seems like Template Toolkit does not know autovivification, and the DEFAULT keyword is similar to the //= assignment operator in Perl.
We can then push the first element of item into the array ref we just created (if it didn't exist yet) inside the hash ref element with the key item.1.name inside by_name.
Once we're done preparing, the rest is just a simple loop. We iterate the sorted keys of by_admin, and then iterate the array ref that's behind that key.
Here's the output:
bar -> 3
foo -> 1
foo -> 2
foo -> 4
It would make sense to do the preprocessing not in a template, but in your controller instead. As normal Perl code it should be easier to read.
my %by_admin;
for my $group (#$groups) {
push #{ $by_admin{ $group->[1]{name} } }, $group->[0];
}
Note that I have omitted use strict and use warnings for brevity.
You will need to rework your code significantly to make this possible.
Keys in Perl hashes are strings, not scalars. Using anything that isn't a string as a key in a hash (e.g, $gr in the expression { $gr => $gra } will cause it to be stringified, just as if you had interpolated it into a string or printed it. Unless you have explicitly overloaded the "" operator on the My::Model::Group object, the key will end up being stored as a literal string along the lines of:
"My::Model::Group=HASH(0x1234567890)"
This string cannot be converted back to the original object -- in fact, the original object was probably garbage-collected as soon as it went out of scope, so it no longer exists at all.
Consider storing the pair as an array reference instead, e.g.
push #$groups, [$gr, $gra];
I am trying to capture an array from my MongoDB database into my Perl script and read each element. This is something that I thought would be simple, but for some dumb reason it is kicking my rearend.
My MongoDB Document (in part)
"members" : [
"5713b2d46d210e51836de591",
"me",
"you",
"him",
"her"
],
Perl code
$document = $database -> get_collection('my_collection')->find_one({_id => $oid});
#members = $document->{'members'};
print Dumper #members;
foreach $member (#members)
{
print "member = $member\n";
}
exit;
Output I am getting:
$VAR1 = [
'5713b2d46d210e51836de591',
'me',
'you',
'him',
'her'
];
member = ARRAY(0x47fa398)
Looking at the last line I see that I am being passed a reference to the array instead of the values. So I tried accessing via $member[0] or $member[1] but that just returns the same ARRAY(0x*****).
PLEASE HELP, I am sure it is something stupid.
Thanks!
Steven
I'm not familiar with Mongo, but looking at the output, your #members array has one element - an array ref (as you suspected). Since Mongo is returning an arrayref, you're best to store that in a scalar and access it like so;
my $members = $document->{'members'};
print "second item returned is: ", $members->[1];
print "The complete contents:\n";
for my $item ( #$members ) {
print " ", $item;
}
I have a problem, right now Im using this foreach loop on CakePhp on which I want to add all the values which are still not on the table for the respecting user. To give a little more context, the user has a menu. And the admin can select which one to add for the user to use. On the next code I receive a array with the menus which will be added as so:
//This is what comes on the ['UserMenuAccessibility'] array:
Array ( [menu_accessibility_id2] => 2 [menu_accessibility_id3] => 3 [menu_accessibility_id4] => 4 [menu_accessibility_id5] => 5 [menu_accessibility_id8] => 8 )
I get the ids of the menus which want to be added to the table for the user to use. And I use the next code to add the menus to the table if they are not there still:
//I check if the array has something cause it can come with no ids.
if (!(isset($this->request->data['UserMenuAccessibility']))) {
$this->request->data['UserMenuAccessibility'] = array();
}
$UserMenuAccessibility = $this->request->data['UserMenuAccessibility'];
foreach ($UserMenuAccessibility as $key => $value) {
$conditions = array(
'UserMenuAccessibility.menu_accessibility_id' => $value,
'UserMenuAccessibility.users_id' => $id
);
if ($this->User->UserMenuAccessibility->hasAny($conditions)) {
} else {
$valuemenu['UserMenuAccessibility']['users_id'] = $id;
$valuemenu['UserMenuAccessibility']['menu_accessibility_id'] = $value;
if ($this->User->UserMenuAccessibility->save($valuemenu)) {
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
For some reason the array is only saving the last new id which is not on the table and not the rest. For example if I have menu 1 and 2 and add 3 and 4 only 4 gets added to the table. For some reason I cant add all the missing menu ids to the table. Any ideas why this is happening?
Thanks for the help on advance.
It looks like your code will save each item, but each call to save() is overwriting the last entry added as $this->User->UserMenuAccessibility->id is set after the first save and will be used for subsequent saves. Try calling $this->User->UserMenuAccessibility->create() before each save to ensure that the model data is reset and ready to accept new data:-
$valuemenu['UserMenuAccessibility']['users_id'] = $id;
$valuemenu['UserMenuAccessibility']['menu_accessibility_id'] = $value;
$this->User->UserMenuAccessibility->create();
if ($this->User->UserMenuAccessibility->save($valuemenu)) {
}
In cakephp 2.0 $this->Model->create() create work fine. But if you are using cakephp version 3 or greater then 3. Then follow the below code
$saveData['itemId'] = 1;
$saveData['qty'] = 2;
$saveData['type'] = '0';
$saveData['status'] = 'active';
$saveData = $this->Model->newEntity($saveData);
$this->Model->save($materialmismatch);
In normal case we use patchEntity
$this->Model->patchEntity($saveData, $this->request->data);
It will only save last values of array so you have to use newEntity() with data
In cakephp3, patchEntity() is normally used. However, when using it for inserting-new/updating entries in a foreach loop, I too saw that it only saves the last element of the array.
What worked for me was using patchEntities(), which as explained in the patchEntity() doc, is used for patching multiple entities at once.
So simplifying and going by the original code sample to handle multiple entities, it could be:
$userMenuAccessibilityObject = TableRegistry::get('UserMenuAccessibility');
foreach ($UserMenuAccessibility as $key => $value) {
$userMenuAccessibility = $userMenuAccessibilityObject->get($value);//get original individual entity if exists
$userMenuAccessibilities[] = $userMenuAccessibility;
$dataToPatch = [
'menu_accessibility_id' => $value,
'users_id' => $id
]//store corresponding entity data in array for patching after foreach
$userMenuAccessibilitiesData[] = $dataToPatch;
}
$userMenuAccessibilities = $userMenuAccessibilityObject->patchEntities($userMenuAccessibilities, $userMenuAccessibilities);
if ($userMenuAccessibilityObject->saveMany($requisitions)) {
} else {
$this->Session->setFlash(__('The users could not be saved. Please, try again.'));
}
Note: I haven't made it handle if entity doesn't exist, create a new one and resume. That can be done with a simple if condition.
I have these tables
clientes
id
nombre_rz
ced_rif
telefono
id_usuario
solicitantes
id
nombre
email
telefono
id_cliente
cliente->hasMany('solicitante')<br>
solicitante->belongsTo('cliente')<br>
^ This is well written in the models, just trying not to make a wall of text.
After Authenticating, when i do
$cliente = Cliente::where('usuario_id','=',Auth::id())->with('solicitante')->get();
dd($cliente);
or
$cliente = Cliente::where('usuario_id','=',Auth::id())->with(array('solicitante' => function($query)
{
$query->where('cliente_id', '=', '35');
}))->get();
dd($cliente);
i get this obect
Object from query
And using toArray() i get this
Array from object
And if access index 0 of that array like
$array = $cliente->toArray(); dd($array['0']);
i get
[Index 0 of array][3]
As far as i can see the queries are correct, and the data i need is there, but i don't know why i can't access the object like
$cliente->id; $cliente->telefono, $cliente->solicitante->nombre, $cliente->solicitante->email
It always throws
Undefined property: Illuminate\Database\Eloquent\Collection::$telefono
Can't Understand this behavior.
You are returning an array of objects, because you asked Laravel for a group. You can either do
foreach ($cliente as $client)
{
echo $client->telefono;
foreach ($client->solicitante as $solicitante)
{
$solicitante->nombre;
}
}
OR you can specify that you only want one result
$cliente = Cliente::where('usuario_id','=',Auth::id())->with('solicitante')->first();
echo $cliente->telefono;
foreach ($client->solicitante as $solicitante)
{
$solicitante->nombre;
}