Seed a recursive table using factories in Laravel - 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'
];
});

Related

How to get data from nested relationship in Laravel 8 Eloquent?

How to make a deep relationship with eloquent? I'm trying to display the data like this :
+------------------------------------+
| Main ID | Name | SN | Last Event |
|------------------------------------|
| 12 | James | j89 | RIGHT |
+------------------------------------+
The "Last Event" column is based on the latest data on "Tracks" table but the value "RIGHT" is relation between the "Tracks" table with "Events" table. So, in this table, the latest record in the tracks table is id of 9 with event_id of 12, the event_id of 12 in the Events table has name column that contained value RIGHT. That value that I want to grab it to display in front end. this is my table in database.
Main table
+---------------+
|id | name | sn |
|---------------|
|12 | James| j89|
+---------------+
Tracks table
+-------------------------------------+
|id | main_id | event_id | created_at |
|-------------------------------------|
| 5 | 10 | 10 | 2021-10-12 |
| 9 | 10 | 12 | 2021-11-20 |
+-------------------------------------+
Events
+----------+
|id | name |
|----------|
|10 | LEFT |
|12 | RIGHT|
+----------+
If I use has one relationship with latestOfMany() method, it didn't reach to the events table. How do I reach it to the Events table to grab the value in Events table through the latest data of Tracks table based on main_id? thanks!
you can use Eager Loading to load deep in your relation, if you setup your relation correctly:
class Main extends Model
{
public function latestTrack()
{
return $this->hasOne(Track::class,'main_id')->latestOfMany();
}
}
class Track extends Model
{
public function event()
{
return $this->belongsTo(Event::class,'event_id');
}
}
now you can get the structre you need:
$main=Main::with('latestTrack.event:id,name')->find(12);

Laravel - how to handle ENUMs

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')),

Laravel: Query the models where the relationship is greater than 0

I'm doing a Laravel query to query a list of elements that his relationship is grater than 0.
The table concerts:
| ID | NAME |
|----|-----------|
| 1 | Concert A |
| 2 | Concert B |
| 3 | Concert C |
And the Position table.
| ID | concert_id | user_id | Content |
|----|----------------|------------|----------|
| 1 | 1 | 1 | xxx |
| 2 | 1 | 2 | yyy |
| 3 | 3 | 1 | zzz |
| 4 | 3 | 2 | www |
| 5 | 1 | 3 | xyx |
| 6 | 3 | 3 | rer |
The query that I need to do is, get the concerts where their position has in the content a value like $some_query$.
The code I've is the following:
$result = $this->model->whereHas('positions')
->with(['positions' => function ($query) {
$query->where('content', 'like', "%{$content}%");
}])->get();
But as far as I can tell, this will bring all the concerts, and also this is going to bring only the positions that has the desired content.
So I've two problems, the first one is I need to get the concerts that his queried positions are greather than 0.
And the second one is that also I need to bring all the positions, not only the queried ones.
Basically the query is just a way to know which concerts I need to bring.
Is there possible to achieve this on a single query?
You'll have to move your query to the whereHas.
If I understood well, this is what you want:
$result = $this->model
// Take the Concerts that has positions with a similar content
->whereHas('positions', function ($query) use ($content) {
$query->where('content', 'like', "%{$content}%");
})
// Take (all) the Positions of these concerts
->with('positions')
->get();

Laravel: Proper Querying Many to Many Relationships

I have 2 tables and a third pivot table as follows:
Table 1: Files
id
title
Table 2: Pools
id
title
is_visible (1,0)
Table 3: file_pools
file_id
pool_id
All Models and Relationships are in place.
A File may belong to none, 1 or more pools
A Pool may have none,1 or more files
Now, i would like to create a scope visible in the Model File such that:
the query includes any File that belongs to none or 1,or more active Pools
should not include any File that has at least 1 invisible (is_visible=0) Pool, even if this File belongs to another visible Pool
Below is what I have tried but this includes files that are both in visible and invisible Pools
public function scopeVisible($query)
{
return $query->doesntHave('pools')->orWhereHas('pools', function ($query) {
$query->where('is_visible',1);
});
}
any help highly welcome
EDIT: Add Sample Data
table: files
| id | title |
|----------|---------------|
| 1 | File A |
| 2 | File B |
| 3 | File C |
| 4 | File D |
table: pools
| id | title | is_visible|
|----------|---------------|---------- |
| 1 | Pool 1 | 1 |
| 2 | Pool 2 | 0 |
table: file_pools
| file_id | pool_id |
|----------|---------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 3 | 2 |
The Expected Result : (scope:visible)
| id | title |
|----------|---------------|
| 1 | File A |
| 4 | File D |
Hope this clarifies
If I understand your situation correctly:
public function scopeVisible($query)
{
return $query->whereDoesntHave('pools', function ($query) {
$query->where('is_visible', 0);
});
}

Elasticsearch index with jdbc driver

Sorry my english is bad
I am using elasticsearch and jdbc river. I have two table with many-to-many relations. For example:
product
+---+---------------+
| id| title |
+---+---------------+
| 1 | Product One |
| 2 | Product Two |
| 3 | Product Three |
| 4 | Product Four |
| 5 | Product Five |
+---+---------------+
product_category
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 4 |
| 2 | 5 |
+------------+-------------+
category
+---+---------------+
| id| name |
+---+---------------+
| 1 | Category One |
| 2 | Category Two |
| 3 | Category Three|
| 4 | Category Four |
| 5 | Category Five |
+---+---------------+
I want to use array type.
{
"id": 1,
"name": "Product one",
"categories": {"Category One", "Category Two", "Category Three"}
},
How should I write a sql?
Use elasticsearch-jdbc structured objects with sql, no need to group_concat:
SELECT
product.id AS _id,
product.id,
title,
name AS categories
FROM product
LEFT JOIN (
SELECT *
FROM product_category
LEFT JOIN category
ON product_category.category_id = category.id
) t
ON product.id = t.product_id
Since river has been deprecated since ES v1.5, maybe run a standalone importer is better.

Resources