The probleme is that when dd($responsablle or $type) its shows only first_name
i need to select first_name and id
public function create(){
$responsable = User::all()->pluck('first_name','id');
$type = EventType::all()->pluck('type','id');
return view ('backend.event.create', compact('responsable', 'type'));
}
First use pluck on the Builder instead of retrieving all the records with all their fields then plucking the fields from the Collection:
$responsable = User::pluck('first_name', 'id');
$type = EventType::pluck('type', 'id');
The second arguement is the field you want to key the Collection/array by. The id part is the key of the element:
foreach ($responsable as $key => $value) {
// $key is the 'id' field
// $value is the 'first_name'
}
foreach ($type as $key => $value) {
// $key is the 'id' field
// $value is the 'type'
}
Or to be more useful with the naming:
foreach ($responsable as $id => $first_name) { ... }
foreach ($type as $id => $type) { ... }
Laravel 5.8 Docs - Query Builder - Retrieving Results - Retrieving A List Of Column Values pluck
Laravel 5.8 Docs - Collections - Available Methods - pluck pluck
To be honest, you don't actually have to use pluck() here. If you simply limit the columns being returned via ->select(), you will receive records with their attributes limited to the columns specified:
$users = User::select('first_name', 'id')->get();
$types = EventType::select('type', 'id')->get();
Now, when looping over these, you'll have access to first_name, id and type, id:
foreach($users AS $user){
echo $user->id."|".$user->first_name;
}
foreach($types AS $type){
echo $type->type."|".$type->id;
}
Note, this does return the full Model for User and EventType, but casting to an array will condense that to just an associative array for each record:
$users = User::select('first_name', 'id')->get()->toArray();
dd($users);
/* array:2 [▼
0 => array:2 [▼
"first_name" => "Bob"
"id" => "1"
]
1 => array:2 [▼
"first_name" => "Mike"
"id" => "2"
]
] */
$types = EventType::select('type', 'id')->get()->toArray();
dd($types);
/* array:2 [▼
0 => array:2 [▼
"type" => "Red"
"id" => "1"
]
1 => array:2 [▼
"type" => "Blue"
"id" => "2"
]
] */
Then, when looping, you can access similarly:
foreach($users AS $user){
echo $user["id"]."|".$user["first_name"];
}
// Or, $users[0]["first_name"], etc.
foreach($types AS $type){
echo $type["type"]."|".$type["id"];
}
// Or, $types[0]["type"], etc.
Related
Ny array looks something like this:
Illuminate\Database\Eloquent\Collection {#2052 ▼
#items: array:3 [▼
0 => App\Models\NewsMeta {#2089 ▶}
1 => App\Models\NewsMeta {#2090 ▶}
2 => App\Models\NewsMeta {#2091 ▶}
]
}
If I open up the array 2:
#original: array:7 [▼
"id" => 17
"post_id" => 240231
"news_tag_id" => 5
"meta_name" => "_thumbnail_id"
"meta_value" => "240232"
"created_at" => "2020-08-06 22:34:06"
"updated_at" => "2020-08-06 22:34:06"
]
Now, I looking to get value "240232" given that I've 240231.
How do I search inside array of the object?
Something like: where post_id is 240231 get ts meta_value.
FYI: It's not eloquent or DB query.
Something like this should work:
$postId = 240231;
$metaValue = null;
foreach ($collection as $model) {
if ($model->post_id == $postId) {
$metaValue = $model->meta_value;
break;
}
}
echo $metaValue;
You could also use the collection's seach method:
$postId = 240231;
$metaValue = $collection->search(static function($model, $key) use($postId) {
if ($model->post_id == $postId) {
return $model->meta_value;
}
});
echo $metaValue;
You can use the collection firstWhere() method
$collection->firstWhere('post_id', '240231')['meta_value'] ?? null;
With the data you provided this should return 240232. In a dataset where there is no post_id = 240231 it would return null.
I don't know why I can't figure this out.
In my controller, how can I loop through this array and only get the values for name and url.
both of those values will be passed to insert a new record.
array:3 [▼
0 => array:2 [▼
"name" => "Discogs"
"url" => "https://www.discogs.com/artist/267549"
]
1 => "2"
2 => array:2 [▼
"name" => "Official homepage"
"url" => "http://www.blackmetal.com/~mega/TBD/"
]
]
You can do with this code:
foreach ($array as $value) {
if (is_array($value) && isset($value['name']) && isset($value['url'])) {
// Do whatever you want
}
}
You can try utilising Laravel's collection for this...
$items = collect($array)
->filter(function($item) {
return is_array($item);
});
If you have extra attributes to the ones you listed then you can use map() to for this:
$items = collect($array)
->filter(function($item) {
return is_array($item);
})
->map(function($item) {
return Arr::only($item, [
'name',
'url',
];
});
p.s. don't forget to add use Illuminate\Support\Arr; to use Arr
I'm trying to loop through JSON data in php.
array:2 [
"cart" => array:3 [
0 => array:4 [
"id" => 3
"name" => "ying"
"price" => "4000"
]
1 => array:4 [
"id" => 2
"name" => "yang"
"price" => "4000"
]
2 => array:4 [
"id" => 4
"name" => "foo"
"price" => "5000"
]
]
"total" => 13000
]
I've used the json_decode function and a foreach over the data.
foreach (json_decode($arr) as $item) {
$item['name'];
}
I want to be able to get each "cart" item and the single "total" data but I keep getting an illegal offset error when i try to call things like $item['name']
As written in json_decode doc:
Note: When TRUE, returned objects will be converted into associative arrays.
If you dont pass 2nd argument as true then it will be treated as object as below.
$arr = json_decode($arr);
$names = [];
foreach ($arr->cart as $item) {
$names[] = $item->name;
}
echo $arr->total;// this is how you will get total.
If you pass 2nd argument as true then it will be treated as associative array as below.
$names = [];
$arr = json_decode($arr, true);
foreach ($arr['cart'] as $item) {
$names[] = $item['name'];
}
echo $arr['total'];// this is how you will get total.
In your code, your data is having two main keys viz. cart and total. From which, you are trying to fetch the data of cart which I specified in my answer.
I have a session to save cart info in laravel like this:
$item = [
'id' => 1,
'product_id' => 11
];
$item2 = [
'id' => 2,
'product_id' => 22
];
\Session::push('cart', $item);
\Session::push('cart', $item2);
Now I want delete an Item in array for $id=1:
foreach(\Session::get('cart') as $cart)
{
if($id==$cart['id'])
{
echo 'done';
\Session::forget('cart.' . $i);
}
$i++;
}
It print done but it can not delete that item in list.
what is my wrong?
also I try \Session::pull('card.id', $id);
EDIT
with dd(\Session::get('cart'))
array:4 [▼
2 => array:5 [▼
"id" => 1
"product_id" => "11"
]
3 => array:5 [▶]
4 => array:5 [▶]
5 => array:5 [▶]
]
So I try change the code to this:
foreach(\Session::get('cart') as $key->$cart)
{
if($id==$cart['id'])
{
\Session::forget('cart.' . $key);
}
}
But It can not delete too
I'm pretty sure that cart.{$id} is not a session key, as you're only explicitly setting cart, which is an array. This should work for you instead:
$id = 1; // set from request, etc.
$cartSession = session()->get("cart");
foreach($cartSession AS $index => $cart){
if($index == $id){
unset($cartSession[$index]);
}
}
session()->put("cart", $cartSession);
Essentially, you pull the session to a variable (array), loop that and unset where $index matches $id, then set the remaining array back as "cart".
Note: I'm using session() instead of \Session, which is just Facade vs global function; shouldn't make a difference on which you use, unless below a certain Laravel version (< 5.0 I believe)
How do I flatten a collection with hierarchy self referenced models, tree collections into a single dimension collection. I have a self referencing model having parents and children.
I want the result to return a eloquent collection, not a simple collection or an array. array has been used as result results for easy demonstration
relationships are declared like this.
public function parent()
{
return $this->belongsTo(self::class, 'parent_id');
}
public function parentRecursive()
{
return $this->parent()->with('parentRecursive');
}
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
public function childrenRecursive()
{
return $this->children()->with('childrenRecursive');
}
so when i call the model->childrenRecursive it returns the collection as it should be. like this. i have changed it toArray() to make it easy to read.
array:1 [
0 => array:6 [
"id" => 5
"name" => "I am a child of 1"
"parent_id" => "1"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
"children_recursive" => array:1 [
0 => array:6 [
"id" => 6
"name" => "I am child of 5"
"parent_id" => "5"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
"children_recursive" => array:2 [
0 => array:6 [
"id" => 7
"name" => "I am child of 6"
"parent_id" => "6"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
"children_recursive" => []
],
1 => array:6 [
"id" => 8
"name" => "I am child of 6 too"
"parent_id" => "6"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
"children_recursive" => []
]
]
]
]
]
]
what I want to achieve is the collection to be single dimension. here is how the toArray() to that collection should look like.
array:4 [
0 => array:6 [
"id" => 5
"name" => "I am a child of 1"
"parent_id" => "1"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
],
1 => array:6 [
"id" => 6
"name" => "I am child of 5"
"parent_id" => "5"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
],
2 => array:6 [
"id" => 7
"name" => "I am child of 6"
"parent_id" => "6"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
],
3 => array:6 [
"id" => 8
"name" => "I am child of 6 too"
"parent_id" => "6"
"created_at" => "2016-12-26 13:53:50"
"updated_at" => "2016-12-26 13:53:50"
]
]
I have tried many collection methods like filter, flatMap, flatten and multiple array methods. but haven't found an appropriate solution.
It's a bit late, but I'm going to post what I wish I had been able to find before I ended up writing it myself.
Similar to the original post, I have a recursive parent/child relationship in my categories table (but this could apply to any table with a self-referencing parent_id column). You can set up your Model like this:
Category.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model {
// Relationships
public function parent()
{
return $this->belongsTo('App\Models\Category', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Models\Category', 'parent_id');
}
public function nested_ancestors()
{
return $this->belongsTo('App\Models\Category', 'parent_id')->with('parent');
}
public function nested_descendants()
{
return $this->hasMany('App\Models\Category', 'parent_id')->with('children');
}
// Attributes
public function getFlatAncestorsAttribute()
{
return collect(flat_ancestors($this));
}
public function getFlatDescendantsAttribute()
{
return collect(flat_descendants($this));
}
}
Then somewhere in your application, you need to have a place to put some global helper functions. You could follow the instructions found here, and then just paste in the following helper functions:
Helpers.php
function flat_ancestors($model) {
$result = [];
if ($model->parent) {
$result[] = $model->parent;
$result = array_merge($result, flat_ancestors($model->parent));
}
return $result;
}
function flat_descendants($model) {
$result = [];
foreach ($model->children as $child) {
$result[] = $child;
if ($child->children) {
$result = array_merge($result, flat_descendants($child));
}
}
return $result;
}
The code above will then allow you to use $category->flat_ancestors, which will produce a flat collection of all the category's ancestors, no matter how many there are. Similarly, using $category->flat_descendants will yield a flat collection of all the child categories, and the child's children categories, and so on until all the posterity categories have been accounted for.
Some things to be careful of:
This type of approach could potentially lead to an infinite loop if
you have Category 1 referencing Category 2 as its parent, and
then Category 2 has Category 1 as its parent. Just be careful
that parent/child relationships are incest free :-)
This type of approach also isn't very efficient. It'll be fine for a bunch of
parent/child recursive relationships, but especially for the
flat_descendants functions, the number of database queries grows
exponentially for each generation level.
I didn't find any builtin method into theLaravel collection either. You may try something like this (Use it as a global function or as a dedicated class method, it's up to you. here is the idea):
function flatten($array) {
$result = [];
foreach ($array as $item) {
if (is_array($item)) {
$result[] = array_filter($item, function($array) {
return ! is_array($array);
});
$result = array_merge($result, flatten($item));
}
}
return array_filter($result);
}
Then use it like this:
// When available into global scope as a function
$flattenArray = flatten($arrayFromTheCollection);
This will will recursively flatten. It doesn't prevent duplicates though, so you'll need to filter them out if that's an issue.
In your AppServiceProvider::boot method
use Illuminate\Support\Collection;
//...
Collection::macro('flattenTree', function ($childrenField) {
$result = collect();
foreach ($this->items as $item) {
$result->push($item);
if ($item->$childrenField instanceof Collection) {
$result = $result->merge($item->$childrenField->flattenTree($childrenField));
}
}
return $result;
});
Then
$flattened = $myCollection->flattenTree('childrenRecursive');
// or in the case of the question
$flattened = $model->childrenRecursive->flattenTree('childrenRecursive');
this is my code, it might help ^_^
Collection::macro('flattenTree', function ($childrenField = 'children', $levelAttribute = 'level')
{
$toProcess = $this->items;
$processed = [];
while($item = array_shift($toProcess))
{
$item->$levelAttribute ++;
$processed[] = $item;
if (count($item->$childrenField) > 0) {
$children = array_reverse($item->$childrenField->items);
foreach ($children as $child) {
$child->$levelAttribute = $item->$levelAttribute;
array_unshift($toProcess,$child);
}
}
}
return Collection::make($processed);
});
you should put this code in the boot method of AppServiceProvider.php or any provider you wish, and then you can use it like this
Category::where('parent_category_id', null)->get()->flattenTree();
this will flat the tree and add a level attribute to each object to indicate the depth level of the object
good luck for everyone
For these who does run into a dead loop because of incest relationship, I used this solution to retrieve descendants' attributes through eager loaded relationship - worked like fully flattening the relationship but avoid running into dead loop by foreach.
Solution link