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

kokoshneta's avatar

Is it possible to ‘lazy-determine’ model types in all contexts?

Apologies in advance if this is long.

I’m slowly migrating a running site, and major changes to the database and its (ancient and often idiotic) structure are unfortunately off-limits.

One of the central types of model in the database is publications – but, annoyingly, they’re separated out into four different tables based on publication type: books, journals, chapters and articles. Nearly all properties and functions are the same for all four types. All publications have a resource ID (RID) which is unique across all four tables, and the only way to determine what type of publication something is is by looking at the first digit of this RID; e.g., if it begins with 3, it’s a book; 5, it’s a journal, etc. Routes to display details about publications should always have the same endpoint, e.g., /publications/{RID}.

I’ve made a parent Publication class (which has no corresponding database table and isn't really instantiable, but defines all the properties and methods common to all types of publications) plus four child classes – Book, Journal, Chapter, Article – which are all instantiable (and in some cases override the parent class’s methods for certain things). The goal here is to be able to ask for/inject a Publication class or object, and get an object of the appropriate child class back.

For routes, I’ve made use of explicit model binding (through Route::bind()) to determine which model type should be returned, and that works fine: go to /publications/55555 and it resolves to an article object, while /publications/33333 resolves to a book object. So far, so good.

But what to do when the fetching is relation-based, rather than route-based?

For example, all publications have one or more contributors (authors, editors, etc.) – and vice versa, all contributors have one or more publications. There’s a sort of pivot table which links contributors to publications and shows which role the contributor plays for the given publication:

- table: books
	- rid: 31234
	- title: 'Great Book'

- table: journals
	- rid: 51234
	- title: 'Funny Journal 15'

- table: contributors
	- id: 1234
	- name: 'John Doe'

- ‘pivot’ table: royalties
	- id: 1
	- contributor_id: 1234
	- rid: 31234
	- role: 'author'

	- id: 2
	- contributor_id: 1234
	- rid: 51234
	- role: 'editor'

So in this case, John Doe is author of Great Book and editor of Funny Journal 15. Going from a Book or Journal object and loading contributors shouldn’t be too hard to do through a pivot table (though I haven’t actually implemented it yet)

What I cannot for the life of me figure out, though, is how I can go from a Contributor and load their publications. Essentially, I want to do this:

// In \App\Models\Contributor
public function publications() {
	return $this->belongsToMany(Publication::class, 'royalties', 'contributor_id', 'rid')->withPivot('role');
}

But obviously this won’t work, since it wil try to select from the table publications, which doesn’t exist. The logic used to determine what Publication::class should ultimately resolve to is bound in routing, but not inside models like here. Models have a resolveRouteBinding function, which is defined on the model itself – but again, only for routing (as far as I can tell – but I couldn’t get that to work at all when I tried, so perhaps I’m wrong there?).

Is there some way to achieve this sort of ‘lazy-loading’, one that isn’t limited to routing, but will work as automatically as possible in all contexts where the parent model might be dependency-injected?

0 likes
4 replies
Snapey's avatar

its more work initially, but have you considered using a polymorphic relationship

You could load every existing publication into a table with a subject_type and subject_id column then use the morph relationship to go from publication 3 to App/Book id=25 or publication 4 to App/Journal id=324

kokoshneta's avatar

@Snapey I hadn’t, primarily because I’ve never worked with polymorphic relationships before – in fact only became aware of them a few days ago when reading the Laravel docs. I couldn’t really make sense of the documentation on it at first, so I kind of skipped it. Trying to read more carefully now and see if I can wrap my head around it.

kokoshneta's avatar

@Snapey Having moved on a bit further now, I can unfortunately say that polymorphic relationships wouldn’t be too practical here – not because of anything explicitly stated in the question here, but because it’s not just contributors that have many-to-many relationships with publications that may be of different types.

I tried looking through the tables and figuring out how many places I’d have to implement polymorphism, and I arrived at no less than 18 tables that have publication IDs as foreign keys and would most likely need to be able to pull publications in through relationships.

If only there were a way to define polymorphism by applying logic within the PHP part, rather than retrieving a static value from the database – that would be exactly what I need.

rajeshtva's avatar

@kokoshneta you can write a service for this one and bind them to container as a singleton. then whenever you have to retrieve it you can do it. something like this... But for this define only models...

class CommonType 
{

	public getAType($model){
		// before returning first clone all data into 
		if($model->rid[0] === '3') {
			return new Book($model->toArray());	
   	} else if($model->rid[0] === '5'){
			return new Journal($model->toArray());
		}
	}
}

hope it helpsl

Please or to participate in this conversation.