Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

laracoft's avatar

Extending tables and/or models

I'm hoping there is a way to do something like below:

  1. A number of tables have the same common fields, e.g. name, address, email, I place them in partners table
  2. The tables are customers, suppliers, employees etc
  3. In PHP terms, think of it like, class customers extends partners, class suppliers extends partners etc
  4. I understand the practice is to use roles and permissions to handle a partner being a customer or supplier
  5. But where would I store customer or supplier specific info?
  6. Is there a way I design the tables such that I can call $customer->name without having to write a bunch of attributes?
0 likes
10 replies
laracoft's avatar

@Tray2 thanks, I read the very well written article before, but I did not find an answer to my issue. Instead, I found an answer in my OP.

It appears my pain point was the duplication of attributes over several models. This can be mitigated by traits, i.e. use ExtendsPartners;... Letting it churn in my mind further...

Tray2's avatar

@laracoft

I've analysed a bit more of the points, and I think you are overthinking it a bit.

The information about the person should be in the users table (if they are users of course or a table named appropiatetly if they aren't). Then should then each have a role, customer,supplier, employee and so on. That means that you should a roles table. You don't need to extend anything in your classes, just use a join. eager load or use a view to get the role of the user.

Point five is a bit tricky, but I would use a little trick I call One-to-many With Different Properties . You can read more about that here https://tray2.se/posts/database-design-part-2

As for point six, I recommend using a view in the database, and I just happen to have a post about that too.

https://tray2.se/posts/use-a-view-instead-of-a-complex-eloquent-query-in-your-laravel-application

laracoft's avatar

@Tray2

I did use view to try to overcome this previously, but it did not allow me to create a customer or supplier directly using Laravel (I had to create a partner first, then create a customer), I decided it was going outside the realm of Laravel, aka I'm on my own and that was a red flag.

Apart from that, the reason I kept going in the direction of extending was because I wanted to keep partners table really small now. I'm making the assumption that I don't know what info about partners we need but more will definiltey be added as we progress and that it will likely apply to all partners, e.g. customers, suppliers etc... Since this approach requires me to only touch partners, it will ensure all extended tables are affected (vs other approaches where a human developer may forget to modify some tables).

Another concern of being partner centric and using roles is that all my code will start with Partner::..., I think Customer::.., Supplier::... makes code more readable and probably require less checks (what if I retrieve a partner that wasn't a customer)

I guess it has evolved into a roles vs multiple simliar tables:

  1. Roles: can code be readable and without alot of extraneous checks?
  2. Simliar tables: Is there a DRY way to ensure the whole group of tables gets upgraded without "going outside" Laravel

Hope I'm not being too difficult here, I regularly visit such issues to try and improve my next code base.

Tray2's avatar

@laracoft The view should only be used for reading, not creating or updating, then you need to use the eloquent models like you do when not using a view.

Lumethys's avatar

do not mistaken the Database Table and Application Model, they are not the same

generally, for a database, anything that had the same field, you throw them all in 1 table

Example, lets say i make an app where a User can either be a Student or Developer a Student have school and grade fields, while Developer have company and position fields

Database:

users { id, email, password, full_name}
students { id, user_id, school, grade}
developers {id, user_id, company, position}

every User belongs to the users table only, every Student belongs to the students table only,...

This way, whenever you have any changes in one 1 them, you only worry about 1 table:

-Suddenly, you want to store first_name and last_name instead of full_name? Easy, just change that in the users table,

-You want a students also had a gpa field? easy, just add that to the students table

-You app grow bigger and now you want to support Artist also? Easy, just add another table named artist with field user_id

-Now you want to implement a "sign-in with Google" button? just add google_id in your users table, and every student, dev or artist will enjoy it at the same time

And remember this is only the Database, for for application, you have a number of option:

  • You can use extends like you intent:
  • You can leverage Laravel Eloquent's relationships:
class User.......
{
	//blablabla
			
	public function student() 		// naming is whatever, you can name it studentProfile() to be clearer
	{
		return $this->hasOne(Student::class);
	}

	public function  developer()		// again, you can use something like developerInfomation() if you wish
	{
		return $this->hasOne(Developer::class);
	}
}

class Student.......
{
	//blablabla
			
	public function user()		// or maybe accountCredential()
	{
		return $this->belongsTo(User::class);
	}
}

class Devloper.......
{
	//blablabla
			
	public function user() 
	{
		return $this->belongsTo(User::class);
	}
}
Lumethys's avatar

@laracoft why would you want to avoid it? The whole point of Eloquent is chaining of method, it is created specifically for this

Take a look at this: lets say you have a books table and an authors table, now you want to find the name of "Lord of the Ring"

plain SQL:

SELECT authors.name
FROM 'books' INNER JOIN 'authors' 
	ON books.author_id = authors.id
WHERE books.title = "Lord of the Ring"

Laravel's query builder:

$LotrAuthorName = DB::table('authors')
	->join('books', 'authors.id', '=', 'books.id')
	->select('authors.name')
	->where('books.title', 'Lord of the Ring')
	->get();

and Eloquent ORM:

$authorName = $theBook->author()->name();
Lumethys's avatar
Lumethys
Best Answer
Level 5

@laracoft and to reduce the ->user, you are writing 5 lines of QueryBuilder?

Do you really want to sacrifice db performance, which mean potentially user experience; increase your app complexity, which mean more time and money will be spent, also making expandability and maintainability harder, all because of one less arrow?

On the other hand, as I said, you can name your relationship anything you want

$customer->accountInfo()->name();

does this look more readable to you?

This is how to achieve that:

class Customer ........
{
	public function accountInfo()	//previously user()
	{
		return  $this->belongsTo(User::class);
	}
}

Prioritize your app's structure first, there is no point in "readable code" if your app is a structural mess

Please or to participate in this conversation.