-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Current Implementation
The current implementation of database events in PHPNomad lives within the database layer, emitting events like RecordCreated, RecordDeleted, and RecordUpdated whenever database operations occur. These events are typically handled through shared traits that implement common database operations, making it convenient for developers to receive notifications about data changes.
The Problem
The current approach presents several issues that conflict with PHPNomad's core principles. First, by placing these events in the database layer, we're making assumptions about where data operations occur. This creates an unnecessary coupling between event listeners and database concepts, when these events should really represent data changes at a higher abstraction level.
Furthermore, the current implementation essentially forces developers into using these events whether they want them or not. This violates the nomadic principle of adaptability - our code should travel to fit the developer's needs, not force developers to travel to fit our assumptions.
Violation of Nomadic Principles
The current implementation violates nomadic principles in several ways. By enforcing a specific event pattern, we're creating a rigid structure rather than providing flexible tools. This rigidity makes it harder for developers to implement private datastores or customize event behavior without complex workarounds.
Additionally, by placing these events in the database layer rather than the datastore layer, we're coupling them too tightly to specific implementation details. This makes it harder to use different storage mechanisms or create custom data handling solutions.
Proposed Solution
The solution involves two key changes:
Event Location
First, we should move all data operation events from the database namespace to the datastore namespace. This reflects that these events represent data changes at an abstract level, not specific database operations. This move allows these events to be used by any datastore implementation, whether it's backed by a database, API, or any other storage mechanism.
Trait Separation
Second, we should split our current monolithic operation trait into small pairs - one version with events and one without, for each CRUD operation. This creates a more modular system where developers can choose exactly which functionality they need. Each operation (create, read, update, delete) would have both a basic implementation trait and an event-emitting version that builds upon it.
Benefits
This new approach provides several key advantages. Developers gain fine-grained control over which operations emit events, making it easier to implement private datastores or customize event behavior. The separation also makes the code more maintainable, as each trait has a clear, single responsibility.
The event relocation to the datastore layer better reflects the abstract nature of these operations and makes the events available to any type of storage implementation. This creates a more flexible system that better aligns with nomadic principles.
Implementation Impact
This change represents a breaking change that will be released in a new major version. The clean break from the previous implementation allows us to fully embrace the new design without compromising its benefits or clarity by maintaining backward compatibility. Developers will need to explicitly opt-in to the new version and update their datastores to use the new separated traits when they choose to upgrade.
Conclusion
By moving events to the datastore layer and splitting operation traits into event and non-event versions, we create a more flexible system that better adheres to nomadic principles. This change gives developers more control while maintaining the convenience of automatic event emission where desired. The result is a more adaptable system that truly travels to meet developer needs rather than enforcing a single approach.