I recently wanted to sort parent elements of a collection by using their relationship values so I came across something like this and It works. Do you think this is a suitable method or am I making this overcomplicated?
Basically, I want to sort the Events by their date
Events have one to many with Slots
Any review on this would be appreciated
Cheers
$events = Event::with(['slots' => function ($q) {
$q->orderBy('date');
$q->orderBy('start_time');
}])->active()->get();
$slotArray = [];
foreach($events as $event){
foreach ($event->slots as $slot) {
$slotArray[$slot->id] = [ 'id' => $event->id, 'start_date' => $slot->date, 'start_time' => $slot->start_time];
}
}
//Sort the Array of IDS
usort($slotArray, array($this,"sortByStartDate"));
//Find the New Set of IDS sorted by the Start Date
$sortedEventIDs = [];
foreach($slotArray as $value) {
array_push($sortedEventIDs, $value['id']);
}
$sortedEvents = $events->sortBy(function($model) use ($sortedEventIDs){
return array_search($model->getKey(), $sortedEventIDs);
});
Sort Function
function sortByStartDate($a, $b){
return $a['start_date'] > $b['start_date'];
}
There is an SQL approach, that would look something like this. Create an subselect, fetch the date you want to use and order by it.
Event::with(['slots' => function ($q) {
$q->orderBy('date');
$q->orderBy('start_time');
}])
->addSelect([
'date' => Comment::selectRaw('MAX(start_date)')
->whereColumn('events.id', 'comments.event_id'),
])->orderBy('date');
Simply use Laravel relation and do the same, not as performance optimized but very straight forward aproeach.
$events = Event::with(['slots' => function ($q) {
$q->orderBy('date');
$q->orderBy('start_time');
}])->active()->get();
$events->sortBy(function ($event) {
return $event->slots()->max('start_date');
});
You can use orderBy() function:
$events = Event::orderBy('start_time', 'DESC')->active()->get();
and for the IDs, you can use sortKeys():
$sorted = $events->sortKeys();
$sorted->all();
Related
Let's say I have a model collection that I'm mapping through like this:
$alreadyImported = [];
$players = Players::whereNotIn('id', $alreadyImported)
->get()
->random(25)
->pluck('id');
$groups = $players->map(function ($item, $key) use ($alreadyImported) {
array_merge($alreadyImported, $item->id);
$group = [
'username' => $item['username'],
];
return $group;
});
// $groups is a pivot table with group and players
Why does my $globalList always start at []? How can I carry the already-merged $globalList to the next map iteration?
The player IDs does not matter. It's for show. I am looking to pass the array through the map iterations.
Just use pluck() to get IDs from the collection:
$ids = $players->pluck('id');
Or, if you just need IDs:
$ids = Players::where('banned', false)->pluck('id');
If you're going to add any other data, you don't need to merge it to some array or a collection because map() will create a new collection.
Finally, you don't need to use collect() because get() will return collection.
I am trying to loop in an array but when it comes to the query it gets only the first element, so a little help would be very important.
$data = Offers::whereIn('id_business', $business_id_array)
->where([
'visible' => 'yes',
'delete' => 'no'
])
->where('end_date', '>=', date('Y-m-d h:m:i'))
->orderBy('id', 'desc')
->get();
$data=array($data);
foreach($data as $key => $item) {
$offers = DB::select('the data i need to get WHERE o.`id` = ' . $item[$key]['id']);
}
and this is my problem in here, It gets only the id of the first element
o.`id` = ' . $item[$key]['id']
because you have return the view in side the foreach loop, so it only loop through the first item and return. What you can do with this case is
$data = Offers::whereIn('id_business', $business_id_array)...->get()->toArray();
$offers = array_map(function($item){
$offer = DB::select('the data i need to get WHERE o.`id` = ?', [$item->id]);
return $offer;
},$data);
return view(....,['offers' =>$offers]);
First, you do not need to cast the $data to an array - it will get returned as a collection, which you can iterate through like an array. So you'll be able to use something like this
$offers = Offers::whereIn('id_business', $business_id_array)...->get();
foreach ($offers as $offer) {
$moreData = DB::select('the data i need to get WHERE o.`id` = ?', [$offer->id]);
}
This looks like you are using the id from one table, to get the associated data from another table.
Should there not be a relationship in place, between the two tables?
The answer from #Chris G looks correct, maybe dd($offers) to be certain what is in there.
Mick
I want to create a multidimensional array to save the data according the date and a category as follow. Then i need to display this data in my blade view?what can i do to achieve this.
'2012-05-05' => array(
'suspension' => 52,
'transmission' => '58'
),
'2012-05-05' => array(
'suspension' => 44,
'transmission' => 21
I have done the following in my controller i want a $reportData variable to load the data.
public function loadReports(Request $request)
{
$data = ['2012-05-05','2012-05-06'];
$salesItems = array();
$orderItems = OrderItem::with('spare', 'order')->get();
foreach ($orderItems as $key => $orderItem) {
if ($orderItem->spare->retailer_id == Auth::user()->id) {
array_push($salesItems, $orderItem);
}
}
$categories = App\Categories::all();
foreach ($data as $date) {
foreach ($categories as $category) {
$categoryValue = 0;
foreach ($salesItems as $salesItem) {
if ($date == $salesItem->order->orderDate) {
$categoryValue += $categoryValue + $salesItem->subTotal;
}
}
//error appears as illegal offset type
$reportData[$date][$category]=$categoryValue;
}
}
return View::make('Retailer/reports')->with('categories', $categories)->with('reportData', $reportData);
}
I haven't tested it but looking at your code it seems that you're passing an object as array index key as 2nd level array index:
$reportData[$date][$category] = $categoryValue;
^^^^^^^^^ this is an object
Dump your $category in the foreach loop & check if that is the case: dd($category)
If you're using Eloquent & your Categories Model has a name property, you'll probably want to take each category name as index value:
$reportData[$date][$category->name] = $categoryValue;
The error is occurring due to the fact that you are trying to use an Object as the array's index.
As per the laravel documentation (https://laravel.com/api/4.2/Illuminate/Database/Eloquent/Model.html#method_all) the all method you called here '$categories = App\Category::all();' would have returned an Eloquent Collection.
So when you iterated over the $categories array and referenced $category, you were referencing an object. In PHP an array can only be indexed by either an integer or a string. So you need to change the line of code where the error is to this
$reportData[$date][$category->someVar] = $categoryValue;
Where someVar is the name of a variable on the Eloquent model Category that references its name, such as 'suspension' etc.
While it doesn't answer your question you could use the Eloquent engine to make your life easier:
$orderItems = OrderItem::with('spare', 'order')->get();
foreach ($orderItems as $key => $orderItem) {
if ($orderItem->spare->retailer_id == Auth::user()->id) {
array_push($salesItems, $orderItem);
}
}
can be simplified (and made more efficient) with:
// Store the uid to save the call.
$user_id = Auth::user()->id;
// Apply the condition to the Eloquent query.
$orderItems = OrderItem::with(['spare' => function($query) use ($user_id) {
return $query->where('retailer_id', '=', $user_id);
}, 'order'])->get();
The other answers are correct, but you probably also want to initialise the $reportData array as before you start working with it.
I am using Laravel and I want to retrieve the data using Eloquent.
My controller:
public function getquesdet(){
$id = Request::input('id');
$question = Question::where('q_id','=',$id)->with('qtags.tags')->with('comments')->with('answers')
->first();
$i=0;
$tagnames[]=0;
foreach ($question['qtags'] as $value) {
$tagnames[$i] = $value['tags']['tag'];
$i++;
}
$j=0;
$comments[]=0;
foreach ($question['comments'] as $value) {
$comments[$j] = $value['comment'];
$j++;
}
$k=0;
$answers[]=0;
foreach ($question['answers'] as $value) {
$answers[$k] = $value['answer'];
$k++;
}
return array('question'=>$question['title'],'body'=>$question['body'],'tags'=>$tagnames,'comments'=>$comments,'answer'=>$answers);
}
As you can see, I feel that the usage of foreach loops is not efficient. Using for loops might take more time. All I want is to know that if there is any efficient workaround to this.
The $question is returned as :
I think that looks like an efficient solution. Three for loops after each other gives complexity O(3n) -> O(n) which is good and should be fast. If you have very large collections of comments, tagnames and questions I would try to solve the problem at SQL level which should be even faster, but for small resultsets this should be good enough.
Big O notation
If you want selected columns from the table then you can use select() method as:
$question = Question::where('q_id','=',$id)
->select('title', 'body')
->with([
'qtags' => function($q) {
$q->select('tag');
},
'qtags.tags' => function($q) {
$q->select('comment');
},
'answers' => function($q) {
$q->select('answer');
}
])
->first();
Then you can return it as an array:
return $question->toArray();
Docs
Can someone show me how to write this query in Eloquent?
SELECT * FROM `projects` WHERE `id`='17' OR `id`='19'
I am thinking
Project::where('id','=','17')
->orWhere('id','=','19')
->get();
Also my variables (17 and 19) in this case are coming from a multi select box, so basically in an array. Any clues on how to cycle through that and add these where/orWhere clauses dynamically?
Thanks.
You could do in three ways. Assume you've an array in the form
['myselect' => [11, 15, 17, 19], 'otherfield' => 'test', '_token' => 'jahduwlsbw91ihp'] which could be a dump of \Input::all();
Project::where(function ($query) {
foreach(\Input::get('myselect') as $select) {
$query->orWhere('id', '=', $select);
}
})->get();
Project::whereIn('id', \Input::get('myselect'))->get();
$sql = \DB::table('projects');
foreach (\Input::get('myselect') as $select) {
$sql->orWhere('id', '=', $select);
}
$result = $sql->get();
The best approach for this case is using Laravel's equivalent for SQL's IN().
Project::whereIn('id', [17, 19])->get();
Will be the same as:
SELECT * FROM projects WHERE id IN (17, 19)
This approach is nicer and also more efficient - according to the Mysql Manual, if all values are constants, IN sorts the list and then uses a binary search.
In laravel 5 you could do it this way.
$projects = Projects::query();
foreach ($selects as $select) {
$projects->orWhere('id', '=', $select);
}
$result = $projects->get();
This is very useful specially if you have custom methods on your Projects model and you need to query from variable. You cannot pass $selects inside the orWhere method.
public function getSearchProducts($searchInput)
{
$products = Cache::rememberForever('getSearchProductsWithDiscountCalculationproducts', function () {
return DB::table('products_view')->get();
});
$searchProducts = $products->filter(function ($item) use($searchInput) {
return preg_match('/'.$searchInput.'/i', $item->productName) || preg_match('/'.$searchInput.'/i', $item->searchTags) ;
});
$response = ["status" => "Success", "data" => $searchProducts ];
return response(json_encode($response), 200, ["Content-Type" => "application/json"]);
}
use filter functionality for any customize situations.