akeeba / fof

Rapid Application Development framework for Joomla!™ 3 and 4
0 stars 0 forks source link

Question on relations at a distance - Google Groups for FOF not valid #673

Closed webstackdev closed 6 years ago

webstackdev commented 6 years ago

I followed the link for questions / discussion on the main wiki page to the FOF Google Groups. That group is not on Google any longer, and a search for "Akeeba" in Google Groups only turned up Joomla! general development groups. If this is more appropriate in the Joomla! group, I'll ask there.

Is there a way to eager-load relations-at-a-distance? e.g. if I have a highly normalized data model that is pulling through a model:

mainModel |--> secondModel --> thirdModel |--> fourthModel --> fifthModel

And I want to get a property from both thirdModel and fifthModel from a view tied to mainModel, is there any way to eagerly load that relationship besides overriding buildQuery? From experimenting and looking through the code, it seems like I'm limited to eagerly loading just secondModel and fourthModel using with(), but I'm not sure.

nikosdion commented 6 years ago

The forum had to be removed because of GDPR.

No, what you are doing is not directly possible. The main model can only control eager loading for the 2nd and 4th model. However, the 2nd model controls eager loading for 3rd model and the 4th model controls eager loading for the 5th model. If you really need the whole thirdModel and fifthModel functionality you could use with() in the constructor of secondModel and fourthModel respectively.

I would be very weary at doing nested eager loading, though. For starters it’s slow and consumes a lot of memory. FOF doesn’t use a smart record mapper to create objects as needed (I tried exploring that option but the way Joomla handles database cursors doesn’t lend to that). Concrete models are created for every record. PHP objects are far from being lightweight. Nor only they consume tons of memory, but the creation and destruction of thousands of models triggers some rather nasty effects on PHP’s garbage collector.

On top of that, having to put yourself in that position is a “smell” in two ways.

First, it’s a sign that there is over-normalization of the data. For example, a typical problem is having invoice rows in a separate table to the invoice proper. This is wrong because you will never address an invoice row outside the context of its invoice. This is best handle in a “noSQL” approach, something MySQL only added in 5.6 and not very well supported inside Joomla. A simple workaround is storing a JSON document and mapping it to objects, if necessary, with custom code. It’s a bit of a kludge though so I can definitely see why using a separate table may still be appealing (and why I used that approach for my ticket system, for example).

The other “smell” is that you only need specific information from the leaf models which might be better provided by a helper. Depending on the use case you might do lazy loading or you might collect all the key values, array_unique them and do a quick database query to fetch relevant information. For example, in my ticket system I am using a helper to get user information. The additional queries were adding less overhead (memory and CPU) than eager loading user information from the ticket posts rows.

Relations and models are tools. They are not fetishes. If they are not the right tool for the job you don’t have to use them. If unsure, you can try eager loading the thirdModel from the secondModel and profile your application. Then try using a helper instead and see if that helps with the performance.

webstackdev commented 6 years ago

Hi Nicholas,

Thanks for taking time to write a detailed answer. I'm enjoying working with the FOF framework, it's a significant improvement over Joomla! MVC imo. The normalization in my domain model is being driven by other considerations, so I'll look at the other approaches.