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.
Related
How to get only one value in the filament table for with hasMany relationship?
I have two DB tables:
products
id
sku
1
SKU_1
2
SKU_2
product_descriptions
id
product_id
translation_id
name
1
1
1
Opel
2
1
2
Vauxhall
In my Product model I have hasMany relationship
public function productDescriptions(): HasMany
{
return $this->hasMany(ProductDescription::class);
}
When I do Tables\Columns\TextColumn::make('productDescriptions.name') it return all values separated by comma. In my example "Opel, Vauxhall"
Is there any way to manipulate/mutate return value using callback? Let say, return only first value "Opel"?
You can use calculated states.
Tables\Columns\TextColumn::make('productDescriptions.name')
->getStateUsing( function (Model $record){
return $record->productDescriptions()->first()?->name;
});
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.*
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
I have a channel_members table containing channel_id, user_id. I need to get the channel_id if there are multiple rows using that same channel_id which contains multiple user_id that I will provide.
Example:
If there are 5 rows in the table
CHANNEL_ID | USER_ID
2 | 2
2 | 3
2 | 4
3 | 2
3 | 4
I need to get the channel_id which are being used by user_id 2, 3, and 4. So based in the table above that I provided. I should get channel_id 2.
I assume you have already defined your relations uisng models, As per your provided description, channel has many to many relation with user
class Channel extends Model
{
public function members()
{
return $this->belongsToMany('App\User', 'channel_members', 'channel_id', 'user_id');
}
}
Using eloquent realtions you can check existance of related models as
$channels = App\Channel::whereHas('members', function ($query) {
$query->where('id', '=', 2);
})->whereHas('members', function ($query) {
$query->where('id', '=', 3);
})->whereHas('members', function ($query) {
$query->where('id', '=', 4);
})->get();
Above will return you only channels who have associations with all 3 users based on supplied id
Querying Relationship Existence
SELECT CHANNEL_ID
FROM channel_members
WHERE USER_ID in (2,3,4)
GROUP BY CHANNEL_ID
HAVING COUNT(CHANNEL_ID) > 0
I am using Laravels Eloquent ORM and i ran into a little problem with a special relationship. Lets assume i have the following table:
Recipe:
id | ... | ingredient1 | ingredient2 | ingredient3 | ingredient4
Every recipe has exactly 4 ingredients and i get the data from an external source in this specific format, thats why i have the ingredients as columns and not as a normal many-to-many relation.
I could set these up as 4 one-to-many relations, but i want to be able to write $ingredient->usedInRecipes()->get().
With 4 one-to-many relations i would have to write $ingredient->usedInRecipesAsIngredient1()->get(), [...], $ingredient->usedInRecipesAsIngredient4()->get() and merge them after afterwards, which would result in 4 queries.
If you know a good way to join these before querying the database or how to make a 4-to-many relation work please answer!
From the question I can't tell if you have already attempted this or not although as I see it you just need to use a single many-to-many relationship.
Each ingredient presumably has a common set of properties that can all be handled in one table ingredients.
id name created_at updated_at
1 Paprika 01/01/1970 00:00:00 01/01/1970 00:00:00
1 Rosemary 01/01/1970 00:00:00 01/01/1970 00:00:00
1 Basil 01/01/1970 00:00:00 01/01/1970 00:00:00
1 Oregano 01/01/1970 00:00:00 01/01/1970 00:00:00
Then your recipes table
id name created_at updated_at
1 Herb Soup 01/01/1970 00:00:00 01/01/1970 00:00:00
To hold the relationships, a pivot table ingredient_recipe
id recipe_id ingredient_id
1 1 1
2 1 2
3 1 3
4 1 4
Now all you require is a belongsToMany relationship on both your Recipe and Ingredient model.
You can code safeguards to make sure one recipe only ever has 4 relationships with ingredient if you wish but to keep it simple:
Recipe::with('ingredients')->get();
Would retrieve all the ingredients along with the recipe.
You can read more about this relationship in the documentation here.
Without Pivots
If you kept the columns ingredient_1, ingredient_2 and so on in the recipes table you could add something like this to your Recipe model.
public function scopeGetWithIngredients($query)
{
$query->leftJoin('ingredients i1', 'recipes.ingredient_1', '=', 'i1.id')
->leftJoin('ingredients i2', 'recipes.ingredient_2', '=', 'i2.id')
->leftJoin('ingredients i3', 'recipes.ingredient_3', '=', 'i3.id')
->leftJoin('ingredients i4', 'recipes.ingredient_4', '=', 'i4.id')
->select('recipes.name', 'i1.name AS ing_1', 'i2.name AS ing_2');
}
You can then just get the ingredients in your model with
Recipe::getWithIngredients();
I found a solution that seems to work in all my use cases.
In the Recipe model i defined the 4 ingredients as One-to-Many relations and made two helper scope functions.
class Recipe extends Eloquent {
public function ingredient1()
{ return $this->belongsTo('Ingredient', 'ingredient1'); }
public function ingredient2()
{ return $this->belongsTo('Ingredient', 'ingredient2'); }
public function ingredient3()
{ return $this->belongsTo('Ingredient', 'ingredient3'); }
public function ingredient4()
{ return $this->belongsTo('Ingredient', 'ingredient4'); }
public function scopeHasIngredient( $query, Ingredient $ingredient ) {
return $query-> where( 'ingredient1', '=', $ingredient->id )
->orWhere( 'ingredient2', '=', $ingredient->id )
->orWhere( 'ingredient3', '=', $ingredient->id )
->orWhere( 'ingredient4', '=', $ingredient->id );
}
public function scopeWithIngredients( $query ) {
return $query->with('ingredient1', 'ingredient2',
'ingredient3', 'ingredient4');
}
}
class Ingredient extends Eloquent {
public function ingredientForRecipes() {
return Recipe::hasIngredient( $this )->withIngredients();
}
}
To get all recipes for an Ingredient i can now call $ingredient->ingredientForRecipes()->get() and use the ingredients without extra queries.