I've been working with PHP for years but have never really ventured out of procedural programming except when working with things like IPB and Magento. I'm trying to advance to the next level and get a better understanding of application structures, OOP, and some common PHP frameworks. That being said, I apologize if my question sounds immature or technically incorrect, I'm new to all of this.
Anyway, I was thinking about the structure of a simple forum. Forgetting about categories, tags, users, roles, advanced editors/bbcode, etc for now and just focusing on the topics and posts...
Because a topic is essentially a series of linked posts ordered by their created_at column, is there a necessity for an actual topics table or could one not simply have a parent column in the posts table? Topics would be identified as posts with a parent equal to their own id, null or 0; something that would otherwise be unused.
If that were the db schema, how would it be laid out in the code, and if relevant, Laravel? Could you still create a Topic model? What would be the pros and cons to having two models working from a single table?
Lastly, how would you approach it if you were creating it? Would you use two tables? A pivot table? Something else? Please explain why you would implement it that way.
For the database design, self referencing tables are a valid design pattern and useful in cases of nested hierarchies such as Categories that can contain sub-categories that can also contain sub-categories ect ect... In this case sub-categories are categories that have a parent but there is no other distinction between them.
It's up to you to decide if a Topic and Post is an identical entity with a parent-child relationship. Personally the way I define the objects I don't feel they are.
The topic-post relationship you're describing is probably more of a One to Many relationship with the topic being the owner or maybe even a Many to Many relationship. This depends on the answer to, "can your topic have many posts? Can your posts be part of many topics?"
If you answered yes and no, then it is a One to Many with topics being the parent aka owner in the relationship.
If you answered yes and yes, then you have a Many to Many relationship. In SQL these are represented by a table with two columns that reference id's from two tables.
If you answered no and yes, then you have a One to Many with posts being the parent aka owner in the relationship.
In laravel, depending on the relationship, your models would include a method that looks like this:
One to Many:
class Topic extends Eloquent
{
public function posts()
{
return $this->hasMany('Post');
}
}
Laravel One-to-Many Relationships
Many to Many:
In laravel the term "pivot table" refers to the table with references to the other objects.
class Post extends Eloquent
{
public function topics()
{
return $this->belongsToMany('Topic');
}
}
class Topic extends Eloquent
{
public function posts()
{
return $this->belongsToMany('Post');
}
}
Laravel Many-to-Many
Self referencing model:
For a self referencing parent child relationship like I explained before you could create something like this, as you can see it's just a one-to-many and the many-to-one in the same model.
class Category extends Eloquent
{
public function parent()
{
return $this->belongsTo('Category', 'parent_id');
}
public function children()
{
return $this->hasMany('Category', 'parent_id');
}
}
There is also the Polymorphic Relation.
This is useful when you have the same entity with just a different type. For example in this table you can have an insurance policy for an employee and a manager. The personType column in the insurancePolicies table defines who the insurance policy belongs to.
Image from codecommit.com
Our laravel models in this case would look like:
class InsurancePolicy extends Eloquent
{
public function insurable()
{
return $this->morphTo();
}
}
class Manager extends Eloquent
{
public function insurance()
{
return $this->morphMany('InsurancePolicy', 'person');
}
}
class Employee extends Eloquent
{
public function insurance()
{
return $this->morphMany('InsurancePolicy', 'person');
}
}
Most everything of what I've explained can also be found in the laravel docs
Related
In my app, you can create lists of roles that are attached to contacts. So you can assign the contact "Bob" the roles of "Gardener" and "Pet Sitter". Then you can create the list "People" and add "Gardener (Bob)" and "Pet Sitter (Bob)" to it.
I have the following tables:
contacts
id
name
roles
id
name
contact_role (pivot)
id
contact_id
role_id
lists
id
name
contact_role_list (pivot)
id
contact_role_id
list_id
Everything was working smoothly until the second pivot table linked to the first pivot table. My pivot tables are (currently) not having any models so I'm not sure if there is a built-in feature to tackle this in Laravel or if I need to think differently.
I currently have this in my List model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(XYZ::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
Is this even close? What do I put where it says XYZ::class?
Ok, so the below is doing what I want, but is there an even better way to do it? The key to solving my problem was to create a Model for ContactRole and changing extends Model to extends Pivot.
I placed this in my List Model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(ContactRole::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
And this in my ContactRole Model:
public function contact(): BelongsTo
{
return $this->belongsTo(Contact::class);
}
Now I could reach the contact data by using something like this: List::first()->contact_roles->first()->contact
Any way to use with, pivot or similar to tidy this up even more? Thanks!
I like to approach these issues in terms of Models rather than pivots. I think many new Developers in Laravel get over obsessed with what's going on in the Database which is fine, but theres a lot of Magic going on so you can write very simple code that does a lot of Heavy lifting, so that being said if I fully understand your problem
You have a Contacts Model
This model can have many roles
so in your contacts Model you need a role relationship
public function roles()
{
return $this->belongsToMany(Roles::class);
}
next of course you have a role Model (pun intended)
your each role can have many list
public function lists()
{
return $this->hasMany(List::class)
}
then the idea is now that you have roles on contacts and lists on roles you should be able to have many lists through contact
public function lists()
{
return $this->hasManyThrough(List::class, Role::class);
}
I've done similar things before and for your description it seems like that's the approach you might need to take.
I have a Laravel model called "Area" which contains "Elements".
Elements can be different Models (in this case a FreetextElement and a CheckboxElement). The whole thing is hooked up with a polymorphic pivot table,
which contains the area_id, the element_id and the element_type.
The basic relationship works fine.
If I for example say:
$area->freetextElements
Then I get all the freetextElements that are attached to that particular area.
My issue is that I'd like a relationship function, which gets all the elements that are attached to the area, regardless of their model.
Here are the areas relations:
public function freetextElements()
{
return $this->morphedByMany(ElementFreetext::class, 'element', 'coaching_element_area_element');
}
public function checkboxElements()
{
return $this->morphedByMany(ElementCheckbox::class, 'element', 'coaching_element_area_element');
}
//find a better solution for this
public function elements()
{
return array_merge( $this->freetextElements->all(), $this->checkboxElements->all());
}
The last function "elements" is just to illustrate what I'm trying to achieve.
Any suggestions? Thanks in advance.
Best Regards
So I have found a solution to this issue. It's not the cleanest solution.
So I'm still open to any additional feedback, but I thought I leave this here for other people.
I simply created a model for the pivot table entries. Area->Elements is the relationship to the pivot table entries and That pivot table model is related to the individual elements via it's own relation. Now I can chain the relation by saying: Area->Elements->Element. It's not optimal, but it gets the job done.
my base class is post
and many submodel such as : video post , image post
all class have specific attribute & inherit parent attrib
& all class need specific behaviors
Problem
when find on post model elequent give super model(post) instance, its wrong
i need instance of submodel
If I understood you correctly, you need relationships
Add a hasMany relationship to your Post.php model:
public function videos()
return $this->hasMany(App\PostVideo::class);
}
As long as your post_video table has a post_id column that references a post, you can call this relationship like this:
foreach($post->videos as $video) {
// Do something
}
And the inverse relationship:
Add a relationship to your PostVideo.php model:
public function post() {
return $this->belongsTo(App\Post::class);
}
And of course, if you have a video, you can access the post it belongs to by doing:
$video->post
It is looked like you want a single table inheritance. In laravel this could be done manually or use package like nanigans or intrip. To use single table inheritance manually, i could suggest you start with reading this stackoverflow question first. However, notice that single table inheritance put everything in a single table but refered by several models that have different behavior. If this is not what you want, just use simple eloquent queries and models - which already explained by Pistachio.
I have three tables in my database: Users, Books, and Reading. The structure of Reading is:
id, user_id, book_id
Now, I need to access to all the books that the user is reading.
First, I would like to know which kind of relationship is, one to many, many to many, Has Many Through, etc. And what do I have to specify in each model? I mean, in the users model hasMany('Reading') or whatever.
I want to access with something like this: Auth::user()->reading()->books()->get() or something similar.
The kind of relationship where one User can be reading several books and one Book can be read by many users is Many-to-Many relationship.
So, to define such a relation in Laravel you should use belongsToMany method:
class User extends Eloquent
{
function books()
{
return $this->belongsToMany("Book", "Reading", "user_id", "book_id");
}
}
class Book extends Eloquent
{
function users()
{
return $this->belongsToMany("User", "Reading", "book_id", "user_id");
}
}
$books = Auth::user()->books;
Notice, you don't need to call method ->books() but use a property ->books, otherwise you'd have to call it like Auth::user()->books()->get().
I couldn't get related models in many-to-many polymorphic relation saved into database.
$photo = Photo::find(1);
$photo->articles()->attach(2);
something like this wouldn't work and gives
error: Call to undefined method
Illuminate\Database\Query\Builder::articles()'
How to do it the right way?
Models
class Tag extends Eloquent
{
public function articles()
{
return $this->morphedByMany('Article', 'taggable');
}
public function photos()
{
return $this->morphedByMany('Photo', 'taggable');
}
}
class Article extends Eloquent
{
public function tags()
{
return $this->morphToMany('Tag', 'taggable');
}
}
class Photo extends Eloquent
{
public function tags()
{
return $this->morphToMany('Tag', 'taggable');
}
}
Finally got it working... Basically it's polymorphism + many to many relationship combined. I thought it don't require tags table. Taggables table acts as pivot table and tags is the table which contains Tag objects that connect models based on pivot table (taggables table)
Morphing does not Support Many To Many, it is actually a one to one association, it is used to create relations between different Models, so for example if you have Tag Model, the tag model could relate to many different occasions, it could relate to Page Model, to Post Model, to Product Model etc, what it actually achieves is that it allows you to relate to that other model without explicity defining the related model in the DB level, for instance a Tag model could be associated with a Post Model, but then you would need to define in the db, a post_id foreign key, with Polymorphic relations you can relate to that Post Model, without defining the model on the DB level as a specific field:
Polymorphic relations allow a model to belong to more than one other model, on a single association
And in Django Documentation you can clearly see how this association works:
staff
id - integer
name - string
orders
id - integer
price - integer
photos
id - integer
path - string
imageable_id - integer
imageable_type - string
The association from above is: 1 Photo relates to 1 Other Model, but with a different concrete implementation* thus a photo can belong to Staff, or it can belong to an order.