I need to add three tables to MySql but I don't know how to organize them.
My tables are :
apartment
floor
surface
And my relations :
apartment can have many floor
apartment can have many surfaces
floor can have many apartment
floor can have many surfaces
surfaces can have one floor (inside apartment's floors)
surfaces can have one apartment
Surfaces are enter after apartment, so I can't use surfaces floor as my apartment floor.
At the moment I have apartment table and floor table with a pivot table (many to many).
In Mysql, what's the best way to handle this ? And after inside laravel ?
Thank for yourhelp !
Edit : my work on laravel so far (only floor table and apartment table)
In Apartment.php :
public function floors(){
return $this->belongsToMany('App\Models\Copro\Floor');
}
In Floor.php :
public function apartments()
{
return $this->belongsToMany('App\Models\Copro\Apartment');
}
Edit 2 : my migration so far :
Schema::create('surfaces', function (Blueprint $table) {
$table->increments('id');
$table->integer('apartment_id')->unsigned()->index();
$table->foreign('apartment_id')->references('id')->on('apartments')->onDelete('cascade');
$table->integer('floor_id')->unsigned()->index();
$table->foreign('floor_id')->references('id')->on('floors')->onDelete('cascade');
$table->decimal('surface',65, 3);
});
Schema::create('apartments', function (Blueprint $table) {
$table->increments('id');
$table->string('nom');
});
Schema::create('floors', function(Blueprint $table)
{
$table->increments('id');
$table->string('nom');
});
Schema::create('apartment_floor', function(Blueprint $table){
$table->increments('id');
$table->integer('apartment_id')->unsigned()->index();
$table->integer('floor_id')->unsigned()->index();
$table->foreign('apartment_id')->references('id')->on('apartments')->onDelete('cascade');
$table->foreign('floor_id')->references('id')->on('floors')->onDelete('cascade');
});
I can think of below kind of relationships in Laravel, I have not created the sample code although but it should help.
Apartment model:
public function floors() {
return $this->belongsTo('App\Models\Copro\Floor', 'floor_id', 'id');
} /* Many apartments belong to single floor. Single floor can have many apartments.*/
public function surfaces() {
return $this->hasMany('App\Models\Copro\Surface', 'surface_id', 'id');
} /* Single apartment has many surfaces */
Floor model:
public function apartments() {
return $this->hasMany('App\Models\Copro\Apartment', 'apartment_id', 'id');
} /* A floor has many apartments */
public function surfaces() {
return $this->hasMany('App\Models\Copro\Surface', 'surface_id', 'id');
} /* A floor has many surfaces */
Surface model:
public function floor() {
return $this->belongsTo('App\Models\Copro\Floor', 'floor_id', 'id');
} /* Surfaces belong to single floor */
public function apartment() {
return $this->hasMany('App\Models\Copro\Apartment', 'apartment_id', 'id');
} /* Surfaces belong to single apartment */
However, it will bring more clarity to the answers if you can provide table schema or migration schema on the same question. Also, you can mention which kinds of SQL queries you are expecting and want to execute. Thanks. Hope this helps.
EDIT:
I am not having PHP installed right now but below schema can be useful to us to at least give newer and better thoughts.
Floor:
id
flr_number
Apartment:
id
apt_number
flr_id
Surface:
id
apt_id
surface
Floor will have many apartments through surfaces. Therefore we can introduce below method in Floor model.
public function surfaces() {
return $this->hasManyThrough(
'App\Models\Copro\Surface',
'App\Models\Copro\Apartment',
'flr_id', /* Foreign key of Apartments table */
'apt_id', /* Foreign key of Surfaces table */
'id', /* Local key of Floors table */
'id' /* Local key of Apartments table */
);
}
Related
I'm learning Laravel 8.x and I decided to do a website project for our community where we have different sport events for our youth throughout the year. Football, volleyball, basketball, etc.
While I think I managed to get pretty far, I have problems understanding how I should design the matches table.
Here is a partial diagram of my current database, which I will explain in more detail:
Each sport is played in form of tournaments throughout the year. Each tournament can have 1 or more groups and 1 or more playoffs. Depending on teams available we create 1-4 groups and usually to let all kids play longer, but still keep it competitive, we could form 2 different playoffs for each tournament, depending on group positions.
I created Models:
Sport
public function tournaments() {
return $this->hasMany('App\Models\Tournament');
}
Team
public function tournaments() {
return $this->belongsToMany('App\Models\Tournament')->withTimestamps();
}
public function groups() {
return $this->belongsToMany('App\Models\Group')->withTimestamps();
}
public function playoffs() {
return $this->belongsToMany('App\Models\Playoff')->withTimestamps();
}
Group
public function tournaments() {
return $this->belongsToMany('App\Models\Tournament')->withTimestamps();
}
public function teams() {
return $this->belongsToMany('App\Models\Team')->withTimestamps()->withPivot(
'position',
'points',
'wins',
'losses',
'draws',
'off',
'def'
);
}
Playoff
Similar to Groups
Tournament
public function sport() {
return $this->belongsTo('App\Models\Sport');
}
public function groups(){
return $this->belongsToMany('App\Models\Group')->withTimestamps();
}
public function playoffs(){
return $this->belongsToMany('App\Models\Playoff')->withTimestamps();
}
public function teams() {
return $this->belongsToMany('App\Models\Team')->withTimestamps();
}
As groups / playoffs belong to tournaments, I decided to use the group_team / playoff_team as a "team signup to a tournament", instead of creating another table with tournament entries and tournament standings.
What I have problem now is creating the matches table. How should I do it?
Real example would be:
We have a tournament in Basketball. Team A and Team B are both in Group A. They play a match and Team A wins 21:19. Since we are in group stage still, the group_team table should get updated.
With already doing all these many-to-many relationships until this point, I am not sure how to design a match table, which should probably have:
team1_id
team2_id
team1_score
team2_score
group_id (?)
Thank you for suggestions.
I ended up creating Match model:
public function team1() {
return $this->belongsTo(Team::class, 'team1_id');
}
public function team2() {
return $this->belongsTo(Team::class, 'team2_id');
}
public function group() {
return $this->belongsTo(Group::class,);
}
public function playoff() {
return $this->belongsTo(Playoff::class,);
}
with
$table->foreign('group_id')
->references('id')->on('groups')
->onDelete('cascade');
$table->foreign('playoff_id')
->references('id')->on('playoffs')
->onDelete('cascade');
$table->foreign('team1_id')
->references('id')->on('teams')
->onDelete('cascade');
$table->foreign('team2_id')
->references('id')->on('teams')
->onDelete('cascade');
Maybe not the best approach and something I will need to revisit down the line, but it works.
I'm working on a project where I need to create three Many-to-Many relationships between 4 models. Here is how it goes:
FAQ Categories can have many FAQ Subcategories and vice versa.
FAQ Groups can have many FAQ Subcategories and vice versa.
FAQs can have many FAQ groups and vice versa.
To all the database experts out there, how should I design this database schema in Laravel? Should I have three different pivot tables? Should I use polymorphic relationships?
I've used polymorphic relationships before, but I'm struggling with implementing it in this scenario.
I would do something like this:
FAQ Categories Table
Schema::create('faq_categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
Schema::table('faq_categories', function (Blueprint $table) {
$table->unsignedInteger('parent_id')->nullable();
$table->foreign('parent_id')->references('id')->on('faq_categories')->onDelete('cascade');
});
FAQ Groups Table
Schema::create('faq_groups', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
FAQs Table
Schema::create('faqs', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
As you can see I wouldn't create a FAQ Sub Categories table, because it's cleaner to have a category table referencing itself to a parent category (also important to make that foreign key nullable to be able to create a top level category).
Now to setup the relationships between the tables, we can do this:
FAQ Categories - FAQ Groups (Many to Many)
Schema::create('faq_category_faq_group', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('faq_category_id');
$table->foreign('faq_category_id')->refrences('id')->on('faq_categories')->onDelete('cascade');
$table->unsignedInteger('faq_group_id');
$table->foreign('faq_group_id')->refrences('id')->on('faq_groups')->onDelete('cascade');
});
FAQs - FAQ Groups (Many to Many)
Schema::create('faq_faq_group', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('faq_id');
$table->foreign('faq_id')->refrences('id')->on('faqs')->onDelete('cascade');
$table->unsignedInteger('faq_group_id');
$table->foreign('faq_group_id')->refrences('id')->on('faq_groups')->onDelete('cascade');
});
Should I use polymorphic relationships?
I don't think polymorphic relationship's would make any sense in this scenario. I would stick with standard many to many.
In your model classes you should setup all the relationships like referenced in the docs.
You can do this:
FaqCategory Model
class FaqCategory extends Model
{
/**
* Get the category's parent category.
*/
public function parent()
{
return $this->belongsTo('App\FaqCategory');
}
/**
* Get the category's sub categories.
*/
public function sub_categories()
{
return $this->hasMany('App\FaqCategory', 'parent_id');
}
/**
* Get the category's faq groups.
*/
public function faq_groups()
{
return $this->belongsToMany('App\FaqGroup');
}
}
FaqGroup Model
class FaqGroup extends Model
{
/**
* Get the group's faq categories.
*/
public function faq_categories()
{
return $this->belongsToMany('App\FaqCategory');
}
/**
* Get the group's faqs.
*/
public function faqs()
{
return $this->belongsToMany('App\Faq');
}
}
Faq Model
class Faq extends Model
{
/**
* Get the faq's faq groups.
*/
public function faq_groups()
{
return $this->belongsToMany('App\FaqGroup');
}
}
One concern is whether FAQ Categories and Subcategories should be different tables. Maybe should be the same table in order to give you the option to have more levels in the future.
i.e.
faq_categories(id, parent_id, name etc.)
Then, in my opinion, you need just different pivot tables. I can not see any reason to use polymorphic relationships.
I have an interface which displays a list of communities on the platform. Communities have members and in turn members/profiles can befriend one another. On the listing page each community card needs to display the number of members (in the community) and the number of friends (friends of logged in profile) from those members.
Here's an illustration of how a community card looks like
I'm getting the communities with the members first:
$communities = $loggedInProfile->communities->load('members')->take(15);
And then iterating over the communities and then the members to find out which ones are friends with the logged in user.
foreach ($communities as $key => $community) {
$friends = [];
foreach ($community->members as $member) {
if ($loggedInProfile->isFriendWith($member)) {
array_push($friends, $member);
}
}
$community->members_who_are_friends = $friends;
}
My issue is that this is very taxing in terms of the number of queries when the associations get large. Is there a better way of retrieving these relationships without having to use nested for loops? I'm also indexing all data with Elasticsearch. Would a retrieval of this sort be better with Elasticsearch? Also would this be a good use case for hasThrough?
Update
The members relationship:
public function members()
{
return $this->belongsToMany('App\Profile', 'community_members', 'community_id', 'profile_id')->withTimestamps();
}
The isFriendWith relationship:
public function isFriendWith(Model $recipient)
{
return $this->findFriendship($recipient)->where('status', Status::ACCEPTED)->exists();
}
The check is done on a table called friendships. The status column (which can be either 0 or 1) is checked to see if friends or not.
The findFriendship check:
private function findFriendship(Model $recipient)
{
return Friendship::betweenModels($this, $recipient);
}
Database structure:
-Profiles migration
Schema::create('profiles', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
-Communities migration (the foreign key is the owner of the community)
Schema::create('communities', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('profile_id');
$table->foreign('profile_id')->references('id')->on('profiles');
$table->string('slug')->unique();
});
-Community_members migration
Schema::create('community_members', function (Blueprint $table) {
$table->primary(['profile_id', 'community_id']);
$table->unsignedInteger('profile_id');
$table->foreign('profile_id')->references('id')->on('profiles');
$table->unsignedInteger('community_id');
$table->foreign('community_id')->references('id')->on('communities');
$table->timestamps();
});
-Friendships migration
Schema::create('friendships'), function (Blueprint $table) {
$table->increments('id');
$table->morphs('sender');
$table->morphs('recipient');
$table->tinyInteger('status')->default(0);
$table->timestamps();
});
In your line:
$communities = $loggedInProfile->communities->load('members')->take(15);
load() is used to perform Lazy Eager loading, i.e. you load the members after the communities have been retrieved, resulting in a different query for every community. You could extract the whole data with a single query using with(). Also, take(15) is performed on the resulting collection and not on the query. Try this:
$communities = $loggedInProfile->communities()->with('members')->take(15)->get();
In the Models of a many to many relationship I have accidentally identified the foreign key names in reverse. This is done in both related Models so the relationship works. It's in production.
In Articles:
public function categories()
{
return $this->belongsToMany(ArticleCategory::class, 'article_category_article', 'article_category_id', 'article_id');
}
and in ArticleCategory:
public function articles()
{
return $this->belongsToMany(Article::class, 'article_category_article', 'article_id', 'article_category_id');
}
As you can see, both foreign keys are reversed.
It doesn't bother me because it works throughout the project. In the article_category_article table both values are recorded in the 'wrong' column.
But what if I'd like to swap it anyway. The Models are easy, but what about the pivot table? I have tried with a laravel migration:
public function up()
{
Schema::table('article_category_article', function (Blueprint $table) {
$table->renameColumn('article_id', 'temporarily');
$table->renameColumn('article_category_id', 'article_id');
$table->renameColumn('temporarily', 'article_category_id');
});
}
without success, it predictably runs into the error There is no column with name 'temporarily' on table 'article_category_article'
Splitting it up in 2 migration files ran into the same error.
I have the tendency to let it be. The question is: can it be done? I presume swapping the columns inside MySQL (without migrations), re-index the tables and adapt the Models is a possibility. Any ideas? I can test it out on a local server.
Two separate queries work for me:
public function up()
{
Schema::table('article_category_article', function (Blueprint $table) {
$table->renameColumn('article_id', 'temporarily');
$table->renameColumn('article_category_id', 'article_id');
});
Schema::table('article_category_article', function (Blueprint $table) {
$table->renameColumn('temporarily', 'article_category_id');
});
}
I am trying to save data with eloquent relationship.
I have following three tables: User Table, Category Table and Post Table.
Post Table
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->string('heading');
$table->timestamps();
$table->foreign('category_id')->references('id')->on('categories');
$table->foreign('user_id')->references('id')->on('users');
});
Relations:
Category:
public function posts() {
return $this->hasMany('App\Post');
}
Post:
public function user() {
return $this->belongsTo('App\User');
}
public function category() {
return $this->belongsTo('App\Category');
}
User:
public function posts($category) {
return $this->hasMany('App\Post');
}
My Problem is that, how can I save post just by passing the Heading in create function. I want to use the relationship. As an example I want to use this kind of code:
$data = ['heading' => $heading];
$user->posts()->category()->create($data);
Is this possible to do this kind of stuff ?
Or any another simple way to achieve this.
EDIT
I need to create post by using this kind of relationship.
As per the process:
user will fill up the form from which I will get the data along with
the category id.
Now I need to create data for that user related with the given category id.
It's because after you call posts() method you won't get to the model's relation (only the query builder) so you will not access category() relation method. It's because posts are one-to-many relation and you don';t know exacly which record you refer to create data.
EDIT
If you want to create new post entry the the best way to sole this is:
$data = ['heading' => $heading, 'category_id' => $putHereCategoryId];
$user->posts()->create($data);
You'll need to obtain somehow the id of the desire category for the new post's entry.