Laravel - how to handle ENUMs - laravel

Considering "enums", for instance:
gender: male, female
marital status: Single, Married, Separated, Divorced, Widowed
What is the best way to work with them in Models in a Laravel application? How to retrieve the list of possibilities and how to store them?
I tried using a table/model named "parameters". Simplifying, consider two tables:
people
|-----|-------|---------|----------------|
| id | name | gender | marital_status |
|-----|-------|---------|----------------|
| 1 | Clark | 1 | 4 |
| 2 | Bruce | 1 | 3 |
| 3 | Diana | 2 | 3 |
| 4 | Louis | 2 | 4 |
|-----|-------|---------|----------------|
parameters (I called like this, but it could be "domains", "enums", "lists", etc).
|----|----------------|---------|
| id | type | name |
|----|----------------|---------|
| 1 | gender | Male |
| 2 | gender | Female |
| 3 | marital_status | Single |
| 4 | marital_status | Married |
|----|----------------|---------|
But here I faced some doubts: how to create relationship between these models on Laravel, considering that just part of parameters table can be used on relationship? I.e. I shouldn't be able to set $person->gender = 3;
Maybe, the ideal is to create a table for each "type of parameter", but actually, there are lots of parameter types.
Other approach is to hard code the enums as config options, as presented in How to show to handle enums in Laravel?.
So, what is the best way to work with them in a Laravel application?

A static information like gender and marital status should not saved in database, something like this are saved in config files. you could add a new config file to config directory and call it for example general.php then you could save this info in it, like:
<?php
return [
'gender' => [
'male',
'female'
],
'marital_status' => [
'Single',
'Married',
'Separated',
'Divorced',
'Widowed'
]
];
And then after running php artisan config:cache you could call it when you want as config('general.gender').
Also, you could handle them in your migration file as:
$table->enum('gender', config('general.gender'));
Finally, as a validation rule you could do:
'field' => 'in:' . implode(',', config('general.gender')),

Related

Laravel | Return rows in order based off pivot

I have the following setup:
stages:
| id | name | order |
commands:
| id | name | body |
------------------------------=
| 1 | test | phpunit |
| 2 | style | echo "style" |
| 3 | deploy | deploy |
command_stage:
| command_id | stage_id | order |
---------------------------------
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 1 | 2 |
Basically, I would like to create a method on the stage model which allows me to get all of the commands back based off of the order, but commands have a specific order and so do the stages.
So each command is stored under a stage so we know which part to run but each command also has an order in that stage. Now I know I can do something like the following:
$inOrder = collect();
Stage::get()->each(function ($stage) {
$commands = $stage->commands()->orderByPivot('order')->get();
$inOrder->push($commands);
});
return $inOrder;
But I was wondering if there is a nicer way to do this? Or even a way to do this solely on one database hit?
Pre-load and sort the relationship:
$stages = Stage::with(['commands' => function ($subQuery) {
$subQuery->orderBy('command_stage', 'order');
}])->get();
foreach($stages as $stage) {
$inOrder->push($stage->commands);
}
This method of Eager-Loading will reduce the N+1 query issue of doing $stage->commands() inside the foreach() loop.

How to find available dates with query

Could you help me build a query to find free dates in Laravel Eloquent.
So I have two models, Node and Booking.
Models are related by HasMany relations
public function dates()
{
return $this->hasMany(Booking::class, 'object_id', 'nid');
}
The model of booking have the following structure:
| bid | object_id | checkin | checkout |
| 1 | 32 | 2017-04-25 | 2017-04-28 |
| 2 | 32 | 2017-05-01 | 2017-05-09 |
| 3 | 44 | 2017-04-21 | 2017-04-24 |
| 4 | 51 | 2017-05-01 | 2017-05-08 |
My purpose is to find available Nodes between given dates.
So, if I want search one date between (for example created_at) it's simple:
whereBetween(‘created_at’, [$date1, $date2])
But how to create a search query between two dates of checkin and checkout?
You mean something like this?
$query->where('checkin','<=', $date)
->where('checkout','>=', $date);
You could also add it to a scope: Laravel query-scopes

Laravel. How to get relationships where foreign key is an array

I am trying to retrieve database rows with their relationships. However, the local key is an array. Let me explain using an example.
Lets say I have a table of countries and a table of pages. Each country can have many pages. Each page can belong to multiple countries. I do not have the flexibility to change this schema.
pages
+-------------+-----------+
| id | name | countries |
+-------------+-----------+
| 1 | Page 1 | 1 |
+-------------+-----------+
| 2 | Page 2 | 1,2,3 |
+-------------+-----------+
| 3 | Page 3 | 4,5,6 |
+-------------+-----------+
countries
+----+----------------+
| id | name |
+----+----------------+
| 1 | United States |
+----+----------------+
| 2 | United Kingdom |
+----+----------------+
| 3 | Germany |
+----+----------------+
| 4 | France |
+----+----------------+
| 5 | Hong Kong |
+----+----------------+
| 6 | Thailand |
+----+----------------+
| 7 | Belgium |
+----+----------------+
| 8 | Singapore |
+----+----------------+
My model and controller look something like:
country
public function pages()
{
return $this->hasMany(Page::class, 'id', 'countries');
}
MemberController.php
$countries = Country::with('pages')->get();
This is returning all countries, but only Page 1 contains any relationships.
Is there a way to retrieve relationships using a whereIn approach so all three countries will return appropriate pages?
Thanks in advance
Since Page can belong to many Countries, you need to create a pivot table called country_page and remove the countries column.
Then define two belongsToMany() relationships in both models:
public function pages()
{
return $this->belongsToMany(Page::class);
}
If you're not following Laravel naming conventions listed in my repo and you gave the pivot name a custom name, define it too:
public function pages()
{
return $this->belongsToMany(Page::class, 'custom_pivot_table');
}
Something like this ?
$datas = Pages::where( ##your conditions### )->get()->inArray();
$countries = Countries::pluck('name','id'); // return array of id=>name
foreach($datas as $key=>$data) {
$c = [];
foreach(explode(',',$data['countries']) as $country_id) {
$c[]=$countries[$country_id];
//or
$c[]= ['id'=>$country_id,'name'=>$countries[$country_id]];
}
$datas[$key]['countries']= $c;
}

Laravel many-to-many relationship with varying options

I am new to Laravel and am attempting to set up a many to many relationship (at least I think that's what I need)
Essentially each user have preferences there are 7 types of preferences some preferences can have multiple values and some have only one value
Here are the user_pref_options
project_type | ( will be checkboxes on view and have multiple options)
favorite | (a user can have multiple this is a foreign key to another table)
tagline | ( will be checkboxes on view and have multiple options)
bedroom_min | (a single value per user)
bedroom_max | (a single value per user)
sf_min | (a single value per user)
sf_max | (a single value per user)
and here is what the user_pref table has
| id | user_id | pref_option_id | value |
| --- | --- | --- | --- |
| 1 | 1 | 1 | 5 |
| 2 | 1 | 1 | 3 |
| 3 | 1 | 2 | 364 |
| 4 | 1 | 2 | 201 |
| 5 | 1 | 2 | 9 |
| 6 | 1 | 2 | 244 |
| 7 | 1 | 2 | 192 |
| 8 | 1 | 2 | 292 |
| 9 | 1 | 4 | 1 |
| 10 | 1 | 11 | 1 |
| 11 | 1 | 12 | 6 |
| 12 | 1 | 13 | 1628 |
| 13 | 1 | 14 | 9134 |
so that would be 1 users notice how some option types have multiples
sorry I had to lay a lot of background before I ask my question.
I would like to be able to connect the user prefs to the user using Eloquent and am having trouble figuring out which way it should be done..
here is what I have tried
//User model
public function prefs(){
return $this->belongsToMany('App\Pref', 'pref_user', 'user_id', 'pref_id');
}
and
//Pref Model
public function user()
{
return $this->belongsToMany('App\Pref', 'pref_user', 'user_id', 'pref_id');
}
I have taken a look here
I would like to be able to get all the preferences and display them on a view
(I won't bore you by pasting that in here now)
my struggle is that some of the preferences have multiple options and some have single options. How do I retrieve the values
maybe I need to separate each preference type to its own model but that seems like overkill I am open to suggestions
user_pref table makes it difficult to distinguish between your prefs and also sets a lot of overhead data.
So, you can set the single value prefs (bedroom_min, bedroom_max, sf_min and sf_max) in user model or in separated model and retrieve them with user. And for other prefs, many-to-many relation is better and more flexible.
Finally, When you fetch User model, you will get the model and its relations.

Seed a recursive table using factories in Laravel

I have a recursive table in my Laravel DB project that handles a dynamic menu. For testing purposes I want to seed that table with random elements.
A random element of faker library will be okay for the menu name. The problem is how to generate the parent_id numbers that match with any element of that menu table. I'll show you an example:
+---------------------------+
| id | name | parent_id |
+---------------------------+
| 1 | animals | 0 |
|---------------------------|
| 2 | food | 0 |
|---------------------------|
| 3 | dog | 1 |
|---------------------------|
| 4 | potato | 2 |
|---------------------------|
| 5 | monkey | 1 |
+---------------------------+
The random number won't work here, because some entries of the table would't have any associated parent. And since the id is incremental, the id will change anytime. The parent_id must be associated with some id.
I've created the factory for the first level (the parent_id = 0). But I don't know how to continue now.
$factory->defineAs(App\Section::class, 'firstLevelMenu', function($faker) {
return [
'name' => $faker->unique->randomElement([
'animals',
'food'
]),
'parent_id' => '0'
];
});

Resources