Laravel | retrieving collection with relationship and except specific Ids - php

i'm working for a car rental booking system
so my plan is when a customer search if there is a available car in chosen Car Model,
first : get the cars id's already taken for the date chosen by customer
second : get all the cars except the not availavle cars,
$collection = Booking::whereDate('dropoffday', '>' ,$date1)
->whereDate('pickupday' ,'<', $date2)
->get(['car_id'])
;
if ($collection->isEmpty()) {
$cars = Car::with('marques.images')->get();
return Response::json($cars);
}
$taken = [];
foreach ($collection as $car) {
$id = $car->car_id;
array_push($taken,$id);
}
$cars = Car::with('marque.images')->except($taken);
return Response::json($cars);
}
how must i rewrite this line
$cars = Car::with('marque.images')->except($available);
to get all cars with relationship except not available cars

If your relations are set up correctly you can probably use the whereDoesntHave method like this:
$cars = Car::with('marque.images')->whereDoesntHave('bookings', function ($query) use ($date1, $date2) {
$query->whereDate('dropoffday', '>' ,$date1)
->whereDate('pickupday' ,'<', $date2);
})->get();
return Response::json($cars);

Related

Codeigniter add multiple category to a course (Academy-LMS)

I am using Academy LMS Source code is in Github
it's a Learning Management system and it is designed to have one category per course
I want to add multiple categories to one course
In /controllers/API.php I have
// Fetch all the categories
public function categories_get($category_id = "") {
$categories = array();
$categories = $this->api_model->categories_get($category_id);
$this->set_response($categories, REST_Controller::HTTP_OK);
}
// Fetch all the courses belong to a certain category
public function category_wise_course_get() {
$category_id = $_GET['category_id'];
$courses = $this->api_model->category_wise_course_get($category_id);
$this->set_response($courses, REST_Controller::HTTP_OK);
}
then in /models/Api_model.php, I have
// Get categories
public function categories_get($category_id)
{
if ($category_id != "") {
$this->db->where('id', $category_id);
}
$this->db->where('parent', 0);
$categories = $this->db->get('category')->result_array();
foreach ($categories as $key => $category) {
$categories[$key]['thumbnail'] = $this->get_image('category_thumbnail', $category['thumbnail']);
$categories[$key]['number_of_courses'] = $this->crud_model->get_category_wise_courses($category['id'])->num_rows();
}
return $categories;
}
// Get category wise courses
public function category_wise_course_get($category_id)
{
$category_details = $this->crud_model->get_category_details_by_id($category_id)->row_array();
if ($category_details['parent'] > 0) {
$this->db->where('sub_category_id', $category_id);
} else {
$this->db->where('category_id', $category_id);
}
$this->db->where('status', 'active');
$courses = $this->db->get('course')->result_array();
// This block of codes return the required data of courses
$result = array();
$result = $this->course_data($courses);
return $result;
}
then in /model/Crud_model.php, I got
public function get_category_details_by_id($id)
{
return $this->db->get_where('category', array('id' => $id));
}
function get_category_wise_courses($category_id = "")
{
$category_details = $this->get_category_details_by_id($category_id)->row_array();
if ($category_details['parent'] > 0) {
$this->db->where('sub_category_id', $category_id);
} else {
$this->db->where('category_id', $category_id);
}
$this->db->where('status', 'active');
return $this->db->get('course');
}
in SQL course table has a column named category_id int(11) which stores one category per course I've changed it to TEXT format and put comma-separated values like 1,2,3 and used the ways like
$this->db->where_in('category_id',$category_id)
and
$this->db->like('category_id',$category_id)
and
$this->db->where("FIND_IN_SET(".$category_id.",category_id) >", 0);
and got no result I just need courses to have comma-separated values in the category_id column
Simply, I want courses to have multiple categories
DB tables
https://pasteboard.co/JNSxO2kz.png
course table
https://pasteboard.co/JNSy7g0.png
category table
https://pasteboard.co/JNSyhlk.png
category_id table (Mapping Table suggested by #micheal-la-ferla )
https://pasteboard.co/JNSyGGn.png
anybody could help?
The way Academy-LMS is designed, it lets you only add 1 category per course. It limits the user and it can be frustrating.
One workaround which could work is to create a new mapping table with 3 columns as follows:
Field Name | Data Type
------------+------------------
ID | int(11)
Course ID | int(11)
Category ID | int(11)
Obviously you need to have the permission to create new tables to use this workaround. Not sure if this is possible for your implementation of Academy-LMS.
The step above will essentially create a one to many relationship between the course and the category, so that 1 course can then be part of multiple categories. (In reality, this would be a many to many relationship since I am assuming that a category may obviously belong to multiple courses).
Therefore the database design will be similar to the one I created here.
If you implement this change, you would then need to make the following changes to the code you have:
// Get categories
public function categories_get($category_id)
{
if ($category_id != "") {
$this->db->where('category_id', $category_id);
}
$this->db->where('parent', 0);
$categories = $this->db->get('course_id')->result_array();
foreach ($categories as $key => $category) {
$categories[$key]['thumbnail'] = $this->get_image('category_thumbnail', $category['thumbnail']);
$categories[$key]['number_of_courses'] = $this->crud_model->get_category_wise_courses($category['id'])->num_rows();
}
return $categories;
}
Essentially, what I did here was replace the parent in the categories with category_id and category with course_id. Not sure if these are correct. You will need to review these when reading from the database as I never used CodeIgniter.

Laravel 5.3 creating multi dimention array from DB results

Reuqirment
My DB has a table named categories and also a table named products where products table has a row named category_id which make the relationship with categories table. So I wants to show random 7 categories from my categories table and also I needs to show 6 products from each category too.
Framework
Laravel 5.3
What I have done
To fetch 8 random categories
This code work as I wants so no issue with this code segment
$masterCategoryList = Category::where('parent_id', 0)
->where('id', '!=',0)
->inRandomOrder()
->take(8)
->get();
Fetch 6 random products for each selected random Master Category List id $masterCategoryList
So what I have done is
$productsMatcheToMasterCategory = [];
for($a = 0; $a<8; $a++){
$productsMatcheToMasterCategory =
Product::where('category_id',$masterCategoryList[$a]['id'])
->inRandomOrder()
->take(6)
->get();
}
But this only output 6 products which related one category when I use dd($productsMatcheToMasterCategory)after the loop.Like below
Category 01
- Product 01
- Product 02
My expected out put is something like below
Category 01
- Product 01
- Product 02
Category 02
- Product 01
- Product 02
Could anyone please tell me why does this happen.
Thanks
This is because you are just replacing the value inside the array. It is just creating the array with index 0.
$productsMatcheToMasterCategory = [];
for($a = 0; $a<8; $a++){
$output =
Product::where('category_id',$masterCategoryList[$a]['id'])
->inRandomOrder()
->take(6)
->get();
array_push($productsMatcheToMasterCategory, $output)
}
In the way you are doing it, you are overriding the value you previously assigned to the variable. To avoid that, add an empty pair of brackets to the variable to indicate that you assign each result of each query in the loop to a new element in the array.
$masterCategoryList = Category::where('parent_id', 0)
->where('id', '!=',0)
->inRandomOrder()
->take(8)
->get();
$productsMatcheToMasterCategory = [];
for($a = 0; $a < 8; $a ++) {
// here note the $productsMatcheToMasterCategory [] = ...
$productsMatcheToMasterCategory [] = Product::where('category_id',$masterCategoryList[$a]['id'])
->inRandomOrder()
->take(6)
->get();
}
but in that way you have 9 queries, 1 to get the eight categories and 8 to get the products for each category.
Another approach I can think of is by defining the relationships in the models:
class Category extends Model
{
public function products()
{
return $this->hasMany(Product::class, 'category_id');
}
}
class Product extends Model
{
public function category()
{
return $this->belongsTo(Category::class);
}
}
and getting the related products by the method with() constraining the eager loads, wich results in just one query:
$collection = Category::where('parent_id', 0)
->where('id', '!=',0)
->inRandomOrder()
->take(8)
->with([
'products' => function($query) {
$query->inRandomOrder()
->take(6);
},
])
->get();
$array = $collection->toArray();

Laravel: Count number of rows in a relationship

I have the following relationship:
A venue has many offers
A offer has many orders
I have the following Eloquent model to represent this:
class Venue {
public function orders()
{
return $this->hasManyThrough(Order::class, Offer::class);
}
}
I want to determine the total number of orders for venues with location_id = 5 using Laravel's Eloquent model.
The only way I managed to do this is as follows:
$venues = Venue::where('location_id', 5)->with('orders')->get();
$numberOfOrders = 0;
foreach($venues as $venue) {
$numberOfOrders += $venue->orders->count();
}
dump($numberOfOrders); // Output a single number (e.g. 512)
However, this is obviously not very efficient as I am calculating the count using PHP instead of SQL.
How can I do this using Eloquent model alone.
You can use Eloquent. As of Laravel 5.3 there is withCount().
In your case you will have
$venues = Venue::where('location_id', 5)->with('orders')->withCount('orders')->get();
Then access it this way
foreach ($venues as $venue) {
echo $venue->orders_count;
}
Can find reference here: https://laravel.com/docs/5.3/eloquent-relationships#querying-relations
$venues = Venue::with([
'orders' => function ($q) {
$q->withCount('orders');
}
])->get();
then use it this way for getting single record
$venues->first()->orders->orders_count();
Alternatively, you can use this way too for collections
foreach($venues as $venue)
{
echo $venue->order_count;
}
If you are using Laravel 5.3 or above you can use withCount.
If you want to count the number of results from a relationship without
actually loading them you may use the withCount method, which will
place a {relation}_count column on your resulting models. For example:
$venues = Venue::withCount(['orders'])->get;
foreach ($venues as $venue) {
echo $venue->orders_count;
}
You can read more about withCount in the Laravel Documentation.
If you are using lower than 5.3, you can make a custom relation on your Venue model:
public function ordersCount()
{
return $this->belongsToMany('App\Models\Order')
->selectRaw('venue_id, count(*) as aggregate_orders')
->groupBy('venue_id');
}
public function getOrderCount()
{
// if relation is not loaded already, let's do it first
if (!array_key_exists('ordersCount', $this->relations)) {
$this->load('ordersCount');
}
$related = $this->getRelation('ordersCount')->first();
// then return the count directly
return ($related) ? (int) $related->aggregate_orders : 0;
}
which can then be used as: Venue::with('ordersCount');. The benefit of this custom relation is you only are querying the count rather than the querying all of those relations when they are not necessary.

Laravel 5.2 Eloquent foreach loop

I'm in a controller for Laravel 5.2 and am trying to iterate through an eloquent collection of invoice_items, which would translate to something like order items. So, the invoice would act as the order, have it's ordered items (invoice_item), and the invoice_items would list all of the products ordered (product).
Here's what I have:
$id = $value; //from param
$invoice = Invoice::where('id', $id)->get();
$invoice_items = Invoice_item::all()->where('invoice_id', $invoice[0]->id);
$contact = Contact::where('id', $invoice[0]->contact_id)->get();
foreach($invoice_items as $item) {
$products = Product::all()->where('id', $item->product_id);
}
I'm attempting to pull all of the products from that specific invoice (via invoice items), which in this specific case should be two, different products.
What's happening, is when I iterate through using that loop, it's adding the same product twice, whereas it should be adding each product once. Is my logic just wrong here? Or do I need to look at my relationships again or something?
Change your queries to:
$invoice = Invoice::where('id', $id)->get();
$invoice_items = Invoice_item::where('invoice_id', $invoice[0]->id)->get();
$contact = Contact::where('id', $invoice[0]->contact_id)->get();
foreach($invoice_items as $item) {
$products = Product::where('id', $item->product_id)->get();
}
An easier way may be to add a items relation to the InvoiceItems model. E.g.:
public function items()
{
$this->hasOne('Items');
}
Then you can get all the Items from Invoice_item using:
return $invoice_items->items;
You can also try:
$invoice = Invoice::where('id', $id)->get();
$invoice_items = Invoice_item::where('invoice_id', $invoice[0]->id)->get()->lists('product_id');
$contact = Contact::where('id', $invoice[0]->contact_id)->get();
$products = Product::whereIn('id', $invoice_items)->get();
Hopefully, $products will then contain a collection of products for that invoice. No need for a foreach loop.

Laravel Eloquent: Count items model relationship

I'm using Laravel and the Eloquent class. I have three models.
City.php:
public function itineraries() {
return $this->has_many('Itinerary', 'city_id');
}
Itinerary.php:
public function city()
return $this->belongs_to('City');
}
public function type()
{
return $this->belongs_to('Itinerarytype');
}
Itinerarytype.php:
public function itineraries()
{
return $this->has_many('Itinerary');
}
As you can see a city has many itineraries and an itinerary belongs to a city and an itinerary type. The itinerarytype model has many itineraries.
Using the with() method is it possible to get a count of itineraries grouped into itinerary type?
For instance here is what I have so far:
$city = City::with(array('itineraries'))->where_slug($city_slug)->first();
This gets the city which has that slug and all of it's itineraries.
I'd like to get a list like: (where the text is the itinerary type and the number is the count)
History: 10
Entertainment: 5
Outdoor: 6
...
You'd have to use join and a bit of raw sql to achieve that on a performant way:
$city = City::where_slug($slug)->first();
$types = ItineraryType::join('itineraries', 'itineraries.type_id', '=', 'itenerary_types.id')
->where('itineraries.city_id', '=', $city->id)
->group_by('itinerary_types.id')
->order_by('itinerary_count')
->get(array('itinerary_types.*', DB::raw('COUNT(itineraries.id) as itinerary_count')));
foreach ($types as $type) {
print($type->label . ': ' . $type->itinerary_count);
}

Categories