Welcome Guest, Not a member yet? Register   Sign In
Proposal for Model Events Enhancement
#1

Hello,

I would like to propose an enhancement to the model events functionality in CodeIgniter 4. 
My suggestion is to allow closures as event callbacks in addition to the current method-based callbacks. This change would provide greater flexibility and simplicity in handling model events.

Thank you for considering this suggestion.
Best regards
Reply
#2

Show  examples to use?
Simple CI 4 project for beginners codeigniter-expenses ( topic )
Reply
#3

I do not understand the benefits.
What is greater flexibility and simplicity?
Reply
#4

(This post was last modified: 07-31-2024, 12:29 AM by maniaba.)

Hello,

Thank you for your questions. Let me provide an example and explain the benefits of using closures as event callbacks in CodeIgniter 4.

Example

Currently, using method-based callbacks can be somewhat cumbersome. For instance, in the UserModel from CodeIgniter Shield, handling model events like `afterFind` requires defining multiple methods:


PHP Code:
protected bool $fetchIdentities false;
protected 
bool $fetchUserLogs false;

protected 
$afterFind = ['fetchIdentities'];

protected function 
fetchIdentities(array $data) {
    // Method to fetch identities
    return $data;
}

protected function 
fetchUserLogs(array $data) {
    // Method to fetch user logs
    return $data;



Each additional event handling requires a new method. If we want to add another `afterFind` event to fetch user logs, we need to define yet another method:


PHP Code:
protected $afterFind = ['fetchIdentities''fetchUserLogs'];

protected function 
fetchUserLogs(array $data) {
    // Method to fetch user logs
    return $data;



Simplified with Closures

By allowing closures as event callbacks, we can simplify this. Here's how the same functionality can be achieved with closures:

PHP Code:
protected $afterFind[] = function($data) {
   // Logic to fetch user logs
   return $data;
}; 

Additional Example for Relationships

Another example where closures can simplify the code is when defining relationships. Currently, the `hasOne` and `hasMany` methods can look like this:

PHP Code:
protected function hasOne(BaseModel $modelstring $localKeystring $attributestring $foreignKey 'id'): static
{
    $modelClass $model::class;
    $oneKey 'hasOne' $modelClass '.' $localKey '.' $attribute '.' $foreignKey;

    if (isset($this->relationsInfo[$oneKey])) {
        return $this;
    }

    $this->relationsInfo[$oneKey] = [
        'type'      => 'hasOne',
        'model'      => $model,
        'foreignKey' => $localKey,
        'attribute'  => $attribute,
        'parentKey'  => $foreignKey,
    ];

    $this->afterFind[] = fn (array $data): array => $this->relationshipHelper($data$model$localKey$attribute$foreignKeyfalse);

    return $this;
}

protected function 
hasMany(BaseModel $modelstring $localKeystring $attributestring $foreignKey 'id'): static
{
    $modelClass $model::class;
    $manyKey 'hasMany' $modelClass '.' $localKey '.' $attribute '.' $foreignKey;

    if (isset($this->relationsInfo[$manyKey])) {
        return $this;
    }

    $this->relationsInfo[$manyKey] = [
        'type'      => 'hasMany',
        'model'      => $model,
        'foreignKey' => $localKey,
        'attribute'  => $attribute,
        'parentKey'  => $foreignKey,
    ];

    $this->afterFind[] = fn (array $data): array => $this->relationshipHelper($data$model$localKey$attribute$foreignKey);

    return $this;


Using hasMany in Public Methods

Here is an example of how you might use the hasMany method within public methods for fetchIdentities and fetchUserLogs:

PHP Code:
public function identities(?IdentityModel $model null): self
{
    return $this->hasMany($model ?? new IdentityModel(), 'id''identities''user_id');
}

public function 
userLogs(?LogModel $model null): self
{
    return $this->hasMany($model  ?? new LogModel(), 'id''logs''user_id');


However, this approach is limited as you can only set the string name of the method on `afterFind`. With closures, this could be simplified significantly.

Benefits

1. Greater Flexibility: Closures allow you to define event handlers inline, making it easier to see the logic directly associated with the event.
2. Simplicity: Reduces the need to create multiple methods for each event handler, making the codebase cleaner and easier to maintain.
3. Encapsulation: Event logic can be encapsulated within the model itself without polluting the class with multiple methods.


Refactoring with Observer Design Pattern

Additionally, refactoring the event handling using the Observer design pattern would further enhance the flexibility and maintainability of the code.
The Observer pattern allows for more decoupled and scalable event management, where observers (listeners) can be added, removed, or modified independently of the event source.
This approach provides a clean and extensible way to manage events, allowing for greater modularity and separation of concerns.

-------------------------------------------------------------

In summary, using closures can simplify the management of model events, making the code more readable and maintainable.

I hope this clarifies the benefits and usage of closures for model events in CodeIgniter 4.

Best regards
Reply




Theme © iAndrew 2016 - Forum software by © MyBB