laravel collect function is undefined - php

i am getting data from database which in need to group so i am converting database result set in to array and then passing it to laravel collect helper but i gives me error
Call to undefined function collect()
Code
$user_profile=collect(UserProfileItem::where('type', "age_group")->get()->toArray())->groupBy("age_group");
please help me about what i am doing wrong i want to use laravel collections method groupby to group my database result array by "age_group"
like below data group by account_id
[
'account-x10' => [
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
],
'account-x11' => [
['account_id' => 'account-x11', 'product' => 'Desk'],
],
]

You dont need to add collect function as you are already getting a collection. So you need to do it as :
$user_profile = UserProfileItem::where('type', "age_group")->get()->groupBy("age_group");

you need to first get the groups and loop through them and add data in those to the collection
$groups = UserProfileItem::groupBy("age_group")->get();
$collection = collect();
foreach($groups as $group){
$data = UserProfileItem::where('type', $group->type)->get();
$collection->put($group->type , $data);
}
return $collection;

i think for previous version of laravel creating your own group is the only solution
public function getGroupedUser($group="age_group"){
$users = $this->users->keyBy('id')->toArray();
$user_profile=UserProfileItem::where('type', "age_group")->get()->groupBy("age_group");
foreach ($user_profile as $row){
$urow[$row['data']][]=$row;
}
echo "<pre>";
print_r($user_profile);die;
}

Related

title does not exist on the Eloquent builder instance

I know there is question about this but there is not solution that helps me. So, i have table 'About' in database and model About.php. I want retrieve only one column from db such as title, and use this codes:
$abouts = About::orderBy('created_at', 'desc');
return view('about')->with('abouts', $abouts);
and in view:
{{$abouts->title}}
and how solve this problem. i don't want to use foreach loop. is it possible? how?
try Pluck()
The pluck method retrieves all of the values for a given key:
$collection = collect([
['product_id' => 'prod-100', 'name' => 'Desk'],
['product_id' => 'prod-200', 'name' => 'Chair'],
]);
$plucked = $collection->pluck('name');
$plucked->all();
// ['Desk', 'Chair']
in controller:
$titles = About::orderBy('created_at', 'desc')->pluck('title')->all();
return view('about')->with('titles');
in blade use:
{{$titles[0]}}
ref: https://laravel.com/docs/9.x/collections#method-pluck

Laravel merge arrays into one

I have 2 tables and I want to make 1 array of both tables data.
Logic
User has bids
Either user is bidder which results come from bids table based on user_id column
Or user is owner and received bids which comes from projects table based on user_id column
I want to merge this 2 arrays into 1 (regardless of user being bidder or receiving bids, I want get all bids at once)
Code
This is what I have currently, but it's not good solution in case user is both bidder and owner, with current code user will only receive data of his/her bids as bidder only.
$bids = Bid::where('user_id', '=', $user->id)->with(['project', 'project.user', 'user'])->get();
if(count($bids) > 0) {
return response()->json([
'data' => BidsResource::collection($bids),
'message' => 'Your data is ready.'
], 200);
} else {
$projects = Project::where('user_id', $user->id)->pluck('id');
$bids = Bid::whereIn('project_id', $projects)->with(['project', 'project.user', 'user'])->get();
return response()->json([
'data' => BidsResource::collection($bids),
'message' => 'Your data is ready.'
], 200);
}
I have already tried array_merge but it return errors (details below).
// as bidder
$bids1 = Bid::where('user_id', '=', $user->id)->with(['project', 'project.user', 'user'])->get();
// as project owner
$projects = Project::where('user_id', $user->id)->pluck('id');
$bids2 = Bid::whereIn('project_id', $projects)->with(['project', 'project.user', 'user'])->get();
// merge results
$bids = array_merge($bids1, $bids2);
return response()->json([
'data' => BidsResource::collection($bids),
'message' => 'Data is ready.'
], 200);
array_merge Errors
Code above return array_merge(): Expected parameter 1 to be an array, object given
If I add ->get()->toArray(); then it would return Trying to get property 'id' of non-object
Any suggestions?
Update
BidsResource file
public function toArray($request)
{
$arrayData = [
'id' => $this->id,
'amount' => $this->amount ? "$ " .number_format($this->amount, 0) : "$0",
'note' => $this->note,
'attachment' => $this->attachment ? url('images', $this->attachment) : null,
'accepted' => $this->accepted,
'results' => $this->results,
'user' => new UserResource($this->whenLoaded('user')),
'project' => new ProjectsResource($this->whenLoaded('project')),
'chats' => BidChatsResource::collection($this->whenLoaded('chats')),
'created_at' => $this->created_at ? $this->created_at->diffForHumans() : null,
'updated_at' => $this->updated_at ? $this->updated_at->diffForHumans() : null,
];
return $arrayData;
}
In your specific case, the proper and efficient way would be using an OR clause to get the records where either of the conditions is satisfied.
The code would be
$projects = Project::where('user_id', $user->id)->pluck('id');
$bids = Bid::where(function($query) use ($projects, $user){
$query->where('user_id', '=', $user->id)->orWhereIn('project_id', $projects);
})->with(['project', 'project.user', 'user'])->get();
As the results of $bids1 and $bids2 are objects of laravel collection, you can use merge() method of collections#method-merge
$bids = $bids1->merge($bids2);

Return only certain data in from a collection - Laravel

I'm learning Laravel and have created a public endpoint where I want to output only certain information of some comments if a user is not authenticated from a GET request.
I have managed to filter out the comments based on whether or not they are approved. I now want to filter out the data that is returned. I have attached a screenshot of what is currently returned.
Ideally, I only want to return the id, name and the body in the json. How can I go about this? I tried the pluck() method which did not give the desired results. Any pointers would be greatly appreciated
public function index(Request $request)
{
if (Auth::guard('api')->check()) {
return Comment::all();
} else {
$comments = Comment::where('approved', 1)->get();
return $comments->pluck('id','name','body');
}
}
To select the particular columns, you can pass columns name to get as
$comments = Comment::where('approved', 1) -> get(['id','name','body']);
You can use a transformer to map the incoming data to a sensible output based on the auth state. The following example comes from the Fractal lib:
<?php
use Acme\Model\Book;
use League\Fractal;
$books = Book::all();
$resource = new Fractal\Resource\Collection($books, function(Book $book) {
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
'author' => [
'name' => $book->author_name,
'email' => $book->author_email,
],
'links' => [
[
'rel' => 'self',
'uri' => '/books/'.$book->id,
]
]
];
});
Ideally, you would create 2 classes that extend from Transformer and pass the correct one to the output.
If you want to pass the result as json respose
$comments = Comment::where('approved', 1)->pluck('id','name','body')->toArray();
return Response::json($comments);
If you want to pass the result as to blade
$comments = Comment::where('approved', 1)->pluck('id','name','body')->toArray();
return view('your_blade_name')->with('comments',$comments);

Yii2 Query class does not return additional columns

I've got something like this
$query = Customer::find()
->select(['customer.name', 'surname', 'cityName' => 'cities.name', 'streetName' => 'streets.name'])
->joinWith(['city', 'street'])
->where(['group_id' => $id]);
When i do
return $query->all();
it returns only columns from customer table, but when i do something like this
$raw = $query->createCommand()->getRawSql();
return \Yii::$app->user_db->createCommand($raw)->queryAll();
it returns me all 4 columns. Why orm fails?
I'm using custom db connection (user), dynamicly connected after authorization. Anyway ActiveRecord->getDb() has been customized too and it works well till now.
it returns only columns from customer table, but when i do something like this.
Yes, that's right. Because Yii2 AR(Active Record) is ORM pattern. And it's try to return all result off query like object.
So, I will not tell the theory, I'd better suggest a solution variant:
$query = Customer::find()
->joinWith(['city', 'street'])
->where(['group_id' => $id])
->asArray()
->all();
return $query;
It's from Yii2 docs(performance tuning).
The result will be like:
[
all data selected from "customer",
['city' => all data selected from city joinWith],
['street' => all data selected from street joinWith]
]
I think, this is exactly what you need.
But, if you need objects. You can try marge objects to only one array.
$customer = Customer::find()
->joinWith(['city', 'street'])
->where(['group_id' => $id])
->all();
return [
'customer' => $customer,
'city' => $customer->city,
'street' => $customer->street,
];
you are using
->select(['customer.name', 'surname', 'cityName' => 'cities.name', 'streetName' => 'streets.name'])
so you will get selected columns only.
use,
$query = Customer::find()
->joinWith(['city', 'street'])
->where(['group_id' => $id])
->all();
this will give you all the columns

Laravel faker - loop to add records to simulate version control

I am using faker to seed my DB.
$factory->define(App\Product::class, function (Faker\Generator $faker) {
$campaign = factory(App\Campaign::class)->create();
$size= $faker->randomElement($array = array ('728x90','300x250','315x315', '715x425', '750x650'));
return [
'campaign_id' => $campaign->campaign_name,
'size' => $size,
'product_id' => $campaign->campaign_name."_".$size,
'version' => $faker->randomElement($array = array ('1','2','3', '4', '5')),
];
});
The bit I am interested in is the version field. What I would like to do is generate a random number between 1 and 5 and then enter that number of records in the database,
So a product can have been 1 and 5 entries depending on the number of 'versions' which have bene created.
Is this possible?
I tried a simple for loop around the return array with no luck.
From what you say, you want to create multiple entries for the same product with different versions. The Model factory can be used to create a single model entry. You can use the faker directly in the seeder and achieve what you are expecting.
$campaign = factory(App\Campaign::class)->create();
$size= $faker->randomElement($array = array ('728x90','300x250','315x315', '715x425', '750x650'))
$max_version = $faker->randomElement($array = array ('1','2','3', '4', '5'));
for ($version=0; $version < $max_version; $version++) {
Product::create([
'campaign_id' => $campaign->campaign_name,
'size' => $size,
'product_id' => $campaign->campaign_name."_".$size,
'version' => $version,
]);
}
One of the simplest solutions is to create factory method (or trait) in your test class, something like this, you'll get the point :)
public function createProduct()
{
$product = factory(Product::class)->create();
foreach(range(0, $product->version) as $i) {
factory(Version::class)->create([
'product_id' => $product->id
]);
}
return $product;
}

Categories