What to do when models get too fat?

What’s the Yii2 way of keeping models from becoming bloated god-objects? Service components?

Depends on how it became fat… It can became fat also for bad coding, like insetting too much logic in it.

Different fat --> different diet

Some example

Lets say I have certain kind of information which, when saved (either insert or update), trigger some sort of recalculation in other table record.

At first step you will be implementing this by using afterSave() model event.

But a certain point you will see that this action start to incorporate too much code as it start to "touch" many different tables.

Then the correct way is to move everything out of the model and manage as global event decoupling the code in several components which handle the updates.

This is just an example.

Another case is when you start to have complex validator. Move them out in separate components especially when these validation rules do not apply often, like only in particular scenario.

As I was saying different fat different diet.

This is a good example, thank you. So your suggested way is to move this logic into events? This is instead of a application component singleton?

When you start to overload the afterSave model event and it gets fat you will have this code being loaded and compiled even when you just do a search and its execution is not involved, with obvious repercussion on memory usage.

In my opinion afterSave should be always empty, another example can be beforeSave but I would put code in it only if it affect the record itself.

For validation rules is much better to write an external validator rather than writing 20 line of code inside the model.

If you catch the afterSave events globally you are going to have fewer code in the model, the code involved in aftersave happen just when the event is fired, you improve the readability of the code in the model.

Keeping the code slim, make it more readable and contribute to separate the business logic and the code reusability.

Events is only a way to execute code when a certain event happen, The code to be execute can be a controller, a component, or another model update o even a function

http://www.yiiframework.com/doc-2.0/yii-base-event.html#on()-detail

A simple way to manage global event is like the following





class EventsHandler extends Component

{

	public function init() {

    	Event::on(ModelFireEvent::className(), ActiveRecord::EVENT_AFTER_INSERT, ['\components\MyClass', 'methodToExecute']);

	}

}


// and then the method in the external class

	public function methodToExecute($event) {

    	// in $event->sender you have the object (in this case the AR) that fired the event

    	// the rest of my code

	}




In order to register all the events you need to insert the EventsHandler in bootstrap process.

Thanks Roberto.

I wasn’t really asking how to use Events though, but more about if they are the right solution and when to use those say over application components, services, helper classes, etc. Or something. And how should they be organized?

Sorry I misunderstood your question.

Singleton design path (in few word of poor description) is to create a piece of code accessible everywhere in the app and when you need to be sure that there is only one instance of this class, a queue manager for example.

In yii2 for example db connection, and events are singleton class.

Using event or not depends on what are you doing.

I suggested you to use events, but events is not for everything, depend on what you are decoupling.

When

In general I like to keep code clean, therefore when something became too big I prefer to split it in a separate class, it is up to you to know which is the fat limit you can tolerate.

Surely every time when this piece of code can be reused in other contest[b]

[/b]If you make a functionality (I mean a portion of the application like and address book manager) that can be reused in other projects make it as module, you won’t regret this when you start a new project.

How

In general (for both module and application) you will have widgets, validator, helpers and component (widget and validator are higer level component)

Usually what you write is in one of those category.

At application level I suggest you to create a folder for each category.

At module level usually is not necessary (most probably you are going to have just one heleper class) but I suggest you to keep the same organization as this would help a new developer to navigate your code.

Hope this answer your question