In my laravel app I track lesson enrollment and active subscriptions in different tables.
A lesson is defined by lesson_types table which has columns like this:
lesson_types
id | name | sub_plan
Enrollemnts are defined in enrolls table with columns like this:
enrolls
id | user_id | lesson_type_id
and my subscriptions table has columns like this:
subscriptions
id | name | sub_plan | user_id
Tables are connect like this:
enrolls has 'lesson_type_id' which is 'id' of lesson_types table
sub_plan column in lesson_types is the same as sub_plan in subscriptions
Sample database data in tables:
ennrolls
id user_id lesson_type_id
1 1 1
2 1 2
3 2 1
lesson_types
id name sub_plan
1 Lesson 1 plan_1337
2 Lesson 2 plan_1338
3 Lesson 3 plan_1339
subscriptions
id name sub_plan user_id
1 Sub 1 plan_1337 1
I tried to get all enrollments like this:
$enrolled = DB::table('enrolls')->where('user_id', $userId)
->leftJoin('lesson_types', 'id', '=', 'lesson_type_id')
->select('name');
But I need to get them without subscriptions...
What i want to achieve is:
Get all 'lesson_types' names where user is subscribed
Get all 'lesson_types' names where user has enrolled but not subscribed
Get all 'lesson_types' where user is not enrolled
You can Achieve the above scenario using Laravel Eloquent. Laravel has facilitated a lot of more in-built ORM methods. So We don't need to write manual SQL codes. Don't reinvent the wheel
Enrolls Model
namespace App;
use App\User;
use App\LessonType;
use App\Subscription;
use Illuminate\Database\Eloquent\Model;
/**
*
*/
class Enroll extends Model
{
public function lessonType()
{
return $this->belongsTo(LessonType::class);
}
public function users()
{
return $this->hasMany(User::class);
}
}
Lesson Types Model
namespace App;
use App\Enroll;
use App\Subscription;
use Illuminate\Database\Eloquent\Model;
/**
*
*/
class LessonType extends Model
{
public function enrolls()
{
return $this->hasMany(Enroll::class);
}
public function subscription()
{
return $this->belongsTo(Subscription::class, 'sub_plan','sub_plan');
}
}
Subscriptions Model
namespace App;
use App\User;
use App\LessonType;
use Illuminate\Database\Eloquent\Model;
/**
*
*/
class Subscription extends Model
{
public function lessonType()
{
return $this->hasMany(LessonType::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
In Constroller or Repository
LessonType::select('name')->has('subscription.user');
LessonType::select('name')->doesntHave('subscription.user');
LessonType::select('name')->doesntHave('enrolls.users');
FYI :
Laravel Eloquent Relationships
Follow this approaches. Take it as Best Practice
Related
I am working on online reservation system where customer will search for room available with time and number of people. My database table looks like this:
Table: Property
id
property_name
property_number
1
abc property
AB-123
2
def property
DF-343
property_number is unique field
Table: Rooms
id
Room Name
Capacity
property_number
1
Room one
150
AB-123
1
Room two
500
AB-123
2
Room one
500
DF-343
property_number is foreign key from table property
Table: Booking
id
property_number
room_id
book_status
book_start
book_end
1
AB-123
1
active
2021-06-06 10:00:00
2021-06-06 18:00:00
property_number is foreign key from table property
room_d is foreign key from table Room
book_status : completed, pending, running, cancelled. If booking status is completed or cancelled than user should be able to book.
User Search Field
Reservation Date
Reservation Start Time
Reservation End Time
Total no of People
User Submits Specific Property Number
Solution Tried
$property = Property:::where('status','active')->where('property_number',$property_number)->firstOrFail();
$bookings = $property->bookings()
->whereBetween('event_date_start',[$event_start,$event_end])
->orWhereBetween('event_date_end',[$event_start,$event_end])
->orWhere( function ( $query ) use ($event_start,$event_end) {
$query->where('event_date_start' , '<', $event_start)->where('event_date_end','>',$event_end);
})
->get();
Model Structure
Table: **Property**
Class Property extends Model {
public function bookings(){
return $this->hasMany(Bookings::class,'property_number','property_number');
}
public function rooms(){
return $this->hasMany(Rooms::class,'property_number','property_number');
}
}
Table: **Rooms**
Class Rooms extends Model {
public function property(){
return $this->belongsTo(Property::class,'property_number','property_number');
}
public function bookings(){
return $this->hasMany(Bookings::class,'room_id');
}
}
Table: **Bookings**
Class Bookings extends Model {
}
This way it checks only property not every room associated with the property.
How to check if any room is available for booking for provided property.*
I'm wanting to do a joining table but I'm not sure how to set up the relationship in laravel.
I have 3 tables, products, categories, and product_categories. product_categories will consist of the product ID and the category ID. How would I join theses up in a relationship in laravel so I can just call $product->categories() like a normal relationship?
Your relationship will be belongsToMany.
Your products table would be
id | name
Your categories table would be
id | name
your product_categories table would be
id | product_id | category_id
As per relationship in Laravel
Product Model
class Product extends Model
{
protected $table = 'products';
public function categories()
{
return $this->belongsToMany('App\Category','product_categories','product_id','category_id');
}
}
Category Model
class Category extends Model
{
protected $table = 'categories';
public function products()
{
return $this->belongsToMany('App\Product','product_categories','category_id','product_id');
}
}
In controller now
Product::with('categories')->get();
This is a many-to-many relationship.
You can use belongsToMany on both products and categories and it would work. However you also should rename product_categories to follow the rule
use singular table names in alphabetical order
this would be category_product
I'm having two models Project and StartYear I'm having a project_technical_details table which holds most of the project information. So I've following table structure in project_technical_details:
project_id construction_start construction_area floors .....
When we were developing we were storing construction_start as year. i.e. it was hard coded for ex 2012, 2013, 2019 etc...
Now we want to establish a relationship by which we can manipulate data, so we created a model StartYear and we have following table structure:
id year created_at updated_at
so in this model I defined relationship as:
public function projects()
{
return $this->belongsToMany(
'App\Project', 'project_technical_details', 'construction_start', 'project_id');
}
But in this case I want to relate with year column not with the id. How can I achieve it. Thanks.
Your pivot table should look like this:
|------------------------|
| year | project_id | ...|
|------------------------|
Then, in your StartYear model:
public function projects()
{
return $this->belongsToMany(
'App\Project', 'project_techinical_details', 'project_id', 'year'
)
->whereColumn('project_techinical_details.construction_start', 'start_year.year');
}
Hope it helps.
I am using Laravel 5.5. I have a MySQL table implementation that contains
Table: regions
id name
1 NA
2 SA
3 AP
3 ASEAN
The user can create regions and allocate countries to them.
Pivot table: region_countries
id region_id country_id
1 1 1
2 1 2 ....
210 5 1
A country can belong to many regions, as the user can create a custom region, by grouping countries.
Table: countries
id name ....
1 Argentina....
A user belongs to a country, and thus to many regions
Table: Users
id name country_id
1 John Smith 32
My Country class contains:
/**
* Countries have many Regions
*/
public function regions()
{
return $this->hasManyThrough(Region::class, RegionCountry::class);
}
My Region class contains:
/**
* Regions have many Countries
*/
public function countries()
{
return $this->hasManyThrough(Country::class, RegionCountry::class);
}
So for the User class relationships, Is this the correct way to do this?
/**
* A User has a Country
*/
public function country()
{
return $this->belongsTo(Country::class, 'country_id');
}
/**
* A User has many Regions
*/
public function regions()
{
return $this->country()->hasMany(Region::class, 'region_id');
}
And the reverse, Region class has many Users
/**
* Regions have many Countries
*/
public function countries()
{
return $this->hasMany(Country::class, 'country_id');
}
/**
* Regions have many Users
*/
public function users()
{
return $this->countries()->hasMany(User::class, 'country_id');
}
I have two tables with a pivot table
Table tours
id | name | country_id | featured
Table countries
id | name
Pivot Table country_tour
id | country_id | tour_id
I want to to find the tour that has featured column of tours table set to 1 and country_id of country_tour table set to 1.
UPDATED:
You can do it like this using Laravel's query Builder method - whereHas():
Your models should look like this (Many to Many Relationships):
Tour Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tour extends Model
{
public function countries() {
return $this->belongsToMany('App\Country');
}
}
and Country Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Country extends Model
{
public function tours() {
return $this->belongsToMany('App\Tour');
}
}
and now you can fetch the desired results by using the below query:
Tour::where('featured', 1)
->whereHas('countries', function($q) {
$q->where('id', 1);
})
->get();
This will get you the collection of tours with featured = 1 and having country with id = 1.
Hope this helps!
With reference to Saumya Rastogi answer, change the id to countries.id to avoid "column 'id' in where clause is ambiguous" error.
i.e.
From:
Tour::where('featured', 1)
->whereHas('countries', function($q) {
$q->where('id', 1);
})->get()
To:
Tour::where('featured', 1)
->whereHas('countries', function($q) {
$q->where('countries.id', 1);
})->get();