lumen/laravel pluck not working in with relationship - php

I have pivot table vacancy_tag. I tried different options (value,select, lists and etc), but didn't go further than that. My request:
Vacancy::where('id',1)->with(['tags' => function ($q){
$q->select('tags.id')->pluck('id');
}])->get()->toArray();
return this:
"id" => 1,
"title" => "pm",
"tags" => array:2 [▼
0 => array:1 [▼
"id" => 1
]
1 => array:1 [▼
"id" => 2
]
but need this:
"id" => 1,
"title" => "pm",
"tags" => [
1,
2
]
I would like to receive the data result in a query, without using a methods transformation of the collection, if possible.
PS: I slightly corrected the example, need to display all fields of the vacancy + an array of tags.

Related

How to get multiple arrays from an array in php?

I have he next array looks like:
array:50 [▼
0 => array:39 [▶]
1 => array:39 [▶]
2 => array:39 [▶]
]
So I want to get arrays with a value in common, for example:
array:39 [▼
"id" => 121
"user" => 368
]
array:39 [▼
"id" => 121
"user" => 3687
]
array:39 [▼
"id" => 500
"user" => 452
]
I want to get the two arrays with the attribute
id 121, I was trying to looping the array with foreach looks like:
foreach ($info as $val){
foreach($info as $f ){
if($f["id"]==$val["id"]){
//get the multiple arrays
}
}
}
So, I can't get all the arrays, some idea to how can do that?
I'd use a Collection.
collect your array of arrays:
$collection = collect([
[
"id" => 121
"user" => 368
],
[
"id" => 121
"user" => 3687
],
[
"id" => 500
"user" => 452
]
]);
Use the where method to filter based on a specific key's value:
$filtered = $collection->where('id', 121);
$filtered->all();
/*
[
['id' => '121', 'user' => 368],
['id' => '121', 'user' => 3687],
]
*/
Other where-like methods are available. Be sure to read through all of the documentation on Collections, it's full of great examples!
If you're now convinced that you should use Collections for everything, check out Adam Wathan's awesome book (and other resources): Refactoring to Collections (not free)

How to efficiently insert an array as nested set model with Laravel/PHP and MySQL

I am using this package to handle hierarchy data in Laravel: https://github.com/lazychaser/laravel-nestedset
Their is an implemented functionality which provides the opportunity to create new data with a multidimensional array. So I have the following sample array (of a file/directory hierarchy):
array:3 [
"name" => "Folder1"
"type" => "folder"
"children" => array:2 [
0 => array:2 [
"name" => "test1.txt"
"type" => "txt"
]
1 => array:3 [
"name" => "Folder1.1"
"type" => "folder"
"children" => array:2 [
0 => array:2 [
"name" => "file.png"
"type" => "png"
]
1 => array:3 [
"name" => "folder1.1.1"
"type" => "folder"
"children" => array:1 [
0 => array:2 [
"name" => "file.txt"
"type" => "txt"
]
]
]
]
]
]
]
But their are directories with more than 10GB of data which means they have a much higher complexity than the shown example with a deep hierarchy. The database is already filled with over a million rows. And if I try to insert a new array the MySQL immediately runs on 100% CPU and needs about 20 minutes to insert that new structure into the database.
The reason is because it needs to calculate LEFT and RIGHT for nested set considering already existent data in the table.
Is there a more efficient way to insert such hierarchies into the database?
Quick example of adding the left and right items to the various arrays (assuming that the lowest level of the arrays is a row of items, so no need add a left and right to these individual items).
Something like this could be used to add the values
<?php
function array_left_right (&$array, &$counter = 1)
{
if (is_array($array))
{
$array['left'] = $counter++;
foreach($array as $array_key=>&$array_item)
{
array_left_right($array_item, $counter);
}
$array['right'] = $counter++;
}
}
$fred = array(array(array('a', 'b'), array('c', 'd'), array('e', 'f'), array('g', 'h')),array(array('aa', 'ab'), array('ac', 'ad'), array('ae', 'af'), array('ag', 'ah')));
array_left_right($fred);
print_r($fred);

Passing array of arrays to blade

I have a problem to passing array of arrays from controller to view in Laravel. I've done some research but none of topics helped. My tables are Shops, Items, Items Price. Shops contains shop id, which I get for use from url application/id. In Items Price I got information like shop_id , item_id (these two are FK), price. This table shows which items are in which shops. And in Items I have information about items: id ,picture. When I go to application/1, I want site to show items, which are in this specific shop, information.
My controller method:
public function getItems($id)
{
$items=ItemPrice::where('shop_id', $id)->select('item_id')->get()->toArray();
foreach($items as $item)
$products[] = array(Item::where('id',$item)->get()->toArray());
$shops=Shop::all();
return view('shop')->with(compact(['products','shops']));
}
when I debugging array with dd($products); I get:
array:4 [▼
0 => array:1 [▼
0 => array:1 [▼
0 => array:5 [▼
"id" => 1
"name" => "Item1"
"price" => 0.8
"type" => 2
"img_dir" => "svg/d.jpg"
]
]
]
1 => array:1 [▼
0 => array:1 [▼
0 => array:5 [▼
"id" => 2
"name" => "Item2"
"price" => 1.1
"type" => 2
"img_dir" => "svg/d2.jpg"
]
]
]
2 => array:1 [▼
0 => array:1 [▼
0 => array:5 [▼
"id" => 3
"name" => "Item3"
"price" => 3.1
"type" => 5
"img_dir" => "svg/p1.jpg"
]
]
]
3 => array:1 [▼
0 => array:1 [▼
0 => array:5 [▼
"id" => 4
"name" => "Item4"
"price" => 1.56
"type" => 5
"img_dir" => "svg/p2.jpg"
]
]
]
]
In view I do foreach #foreach($products as $product) and I get error:
Trying to get property 'img_dir' of non-object.
Any help would be appreciated.
Try like this
public function getItems($id)
{
$items = ItemPrice::where('shop_id', $id)
->select('item_id')
->pluck('item_id')
->toArray();
$products = Item::whereIn('id', $items)->get();
$shops = Shop::all();
return view('shop', compact('products','shops'));
}
You have some nested arrays in $products. What you think is a product is in fact an array. Maybe if you simplify your $products variable content :
public function getItems($id) {
$items = ItemPrice::where('shop_id', $id)->select('item_id')->get()->toArray();
$products = [];
foreach($items as $item) {
$products[] = Item::where('id',$item)->get();
}
$shops = Shop::all();
return view('shop')->with(compact(['products', 'shops']));
}
Look at this line
$products[] = array(Item::where('id',$item)->get()->toArray());
$products is an array, and you assign a new element which is an array made by the array value of your query (which contains array).
So you have a 3-level nested array which leads to confusion.
Why don't you just send to your blade view $products = Item::where('id',$item)->get(); ?

Get only some fields from array in Laravel requests

In input I have such an array:
array:1 [
"prizes" => array:1 [
1 => array:2 [
"prize_id" => "1"
"priority" => "1"
"some_fields" => "some_value"
]
]
]
In controller, I try to get only two fields:
$request->only([
'prizes.*.priority',
'prizes.*.prize_id'
]);
but i should get this:
array:1 [
"prizes" => array:1 [
"*" => array:2 [
"priority" => array:1 [
0 => "1"
]
"prize_id" => array:1 [
0 => "1"
]
]
]
]
How to get array with needed fields?
You are getting an array as the result because you are using .*. which is saying get ALL priorities for the prizes, which is why it is returning an array instead.
If you use the dot notation, you will access the only priority for the prize.
Like so:
prizes.priority
If you would like to validate for EVERY prize that you get coming in, you will use *. before hand to access each array, like so:
*.prizes.priority
Edit: bit more information here https://laravel.com/docs/master/validation#validating-arrays

Push a set of values to an array based on another unique value in the same array

Question background
Hello, I have the following array of movie crew members:
array:7 [▼
0 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5e9d"
"department" => "Directing"
"id" => 139098
"job" => "Director"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
1 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5ed7"
"department" => "Writing"
"id" => 139098
"job" => "Story"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
2 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5edd"
"department" => "Writing"
"id" => 132973
"job" => "Story"
"name" => "Ben Coccio"
"profile_path" => null
]
3 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5ee3"
"department" => "Writing"
"id" => 139098
"job" => "Screenplay"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
4 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5ee9"
"department" => "Writing"
"id" => 132973
"job" => "Screenplay"
"name" => "Ben Coccio"
"profile_path" => null
]
5 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5eef"
"department" => "Writing"
"id" => 1076793
"job" => "Screenplay"
"name" => "Darius Marder"
"profile_path" => null
]
11 => array:6 [▼
"credit_id" => "52fe49de9251416c750d5f13"
"department" => "Camera"
"id" => 54926
"job" => "Director of Photography"
"name" => "Sean Bobbitt"
"profile_path" => null
]
]
As you can see this is a list of credits I'm getting via the TMDb API. The first step of building the above array was to filter out all jobs that I don't want to display, here's how I did that:
$jobs = [ 'Director', 'Director of Photography', 'Cinematography', 'Cinematographer', 'Story', 'Short Story', 'Screenplay', 'Writer' ];
$crew = array_filter($tmdbApi, function ($crew) use ($jobs) {
return array_intersect($jobs, $crew);
});
My question
I'd like to figure out how to take the above result one step further and combine jobs where the id is the same, so as to end up with something like this, for example:
array:7 [▼
0 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5e9d"
"department" => "Directing"
"id" => 139098
"job" => "Director, Story, Screenplay"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
I have also considered ditching doing this in my logic and instead doing it in my blade template, but I'm not sure how to achieve that.
How would you accomplish this?
You could nicely use Laravel's Collection in such a situation, which has a great number of methods which will help you in this case.
First, turn this array (the one you already filtered on jobs) to a Collection:
$collection = collect($crew);
Second, group this Collection by it's ids:
$collectionById = $collection->groupBy('id');
Now, the results are grouped by the id and transformed to a Collection in which the keys correspond to the id, and the value an array of 'matching' results. More info about it here.
Finally, just a easy script that iterates through all the results for each id and combines the job field:
$combinedJobCollection = $collectionById->map(function($item) {
// get the default object, in which all fields match
// all the other fields with same ID, except for 'job'
$transformedItem = $item->first();
// set the 'job' field according all the (unique) job
// values of this item, and implode with ', '
$transformedItem['job'] = $item->unique('job')->implode('job', ', ');
/* or, keep the jobs as an array, so blade can figure out how to output these
$transformedItem['job'] = $item->unique('job')->pluck('job');
*/
return $transformedItem;
})->values();
// values() makes sure keys are reordered (as groupBy sets the id
// as the key)
At this point, this Collection is returned:
Collection {#151 ▼
#items: array:4 [▼
0 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5e9d"
"department" => "Directing"
"id" => 139098
"job" => "Director, Story, Screenplay"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
1 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5edd"
"department" => "Writing"
"id" => 132973
"job" => "Story, Screenplay"
"name" => "Ben Coccio"
"profile_path" => null
]
2 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5eef"
"department" => "Writing"
"id" => 1076793
"job" => "Screenplay"
"name" => "Darius Marder"
"profile_path" => null
]
3 => array:6 [▼
"credit_id" => "52fe49de9251416c750d5f13"
"department" => "Camera"
"id" => 54926
"job" => "Director of Photography"
"name" => "Sean Bobbitt"
"profile_path" => null
]
]
}
Note: to use this Collection as an array, use:
$crew = $combinedJobCollection->toArray();
There are multiple ways to achieve this, for example: search the array for overlapping id's, but I think this is the easiest way to achieve this.
Goodluck!
Since you are trying to edit the array elements and its size, I believe array_map() or array_filter() won't be a solution to this.
This is what I could come up with...
$jobs = [
'Director', 'Director of Photography', 'Cinematography',
'Cinematographer', 'Story', 'Short Story', 'Screenplay', 'Writer'
];
$crew = [];
foreach($tmdbApi as $key => $member) {
if($member['id'] == $id && in_array($member['job'], $jobs)) {
if(!isset($crew[$key])) {
$crew[$key] = $member;
} else {
$crew_jobs = explode(', ', $crew[$key]['job']);
if(!in_array($member['job'], $crew_jobs)) {
$crew_jobs[] = $member['job'];
}
$crew[$key]['job'] = implode(', ', $crew_jobs);
}
}
}
Hope this answers your question :)

Categories