Problem/Motivation
Historically, "hooks" were Drupal's legacy way for modules to subscribe to and respond to events in a Drupal response lifecycle. In Drupal 8, the Symfony framework was adopted, which uses a more object-oriented Event + EventSubscriber architecture. There has been a lot of discussion in the Drupal community about moving more of the old hook-based logic to this new model.
farmOS provides a mix of both. During the 2.x development cycle (which upgraded from Drupal 7 to Drupal 9) we took advantage of the new EventSubscriber architecture in many places. But we also added some hooks.
The focus of this issue is to document, discuss, and implement replacing our hooks with Events + EventSubscribers and adopting a consistent approach for future implementations.
References:
- https://www.drupal.org/docs/develop/creating-modules/subscribe-to-and-di...
- https://drupal.stackexchange.com/questions/251001/why-is-it-better-to-us...
- https://www.daggerhartlab.com/drupal-8-hooks-events-event-subscribers/
farmOS Events:
- \Drupal\asset\Event\AssetEvent
- \Drupal\data_stream\Event\DataStreamEvent
- \Drupal\farm_map\Event\MapRenderEvent
- \Drupal\quantity\Event\QuantityEvent
farmOS Hooks:
- hook_farm_api_meta_alter()
- hook_farm_entity_bundle_field_info()
- hook_farm_dashboard_panes()
- hook_farm_dashboard_groups()
- hook_farm_ui_theme_region_items()
- hook_farm_update_exclude_config()
Proposed resolution
Let's consider deprecating all hook that farmOS provides, and replace them with Events + EventSubscribers. The first step is to document all of the hooks we currently provide, and think through how they could be replaced. Then, I think we can add Events + EventSubscribers in farmOS 3.x and deprecate our hooks for removal in 4.x. Removal of hooks would be a breaking API change so we can't do that in 3.x.
Remaining tasks
- Document existing hooks provided by farmOS.
- Design
- Implement Events + EventSubscribers to replace our hooks in farmOS 3.x branch.
- Deprecate the hooks in 3.x branch.
- Create change records.
- Remove hooks in 4.x branch.
User interface changes
None.
API changes
farmOS hooks will be replaced with farmOS Events.
Data model changes
None.
Comments
Comment #2
m.stentaWe implemented some Events during the 2.x development cycle for some of core farmOS entities (
asset,quantity, anddata_stream) that allow us to use EventSubscribers instead of core entity hooks like _presave(), _insert(), _update(), _delete(): #3306227: Dispatch events for asset presave, insert, update, delete(Worth noting it looks like we didn't add that for
planentities... so maybe worth tacking on a commit for that with these changes at the same time. Are there other core farmOS entities that should have the same?)Drupal core has an open issue that will ultimately provide the same for all entities automatically (which will allow us to remove our own Events): #2551893: Add events for matching entity hooks
Comment #3
m.stentaI took a pass through all modules included with farmOS and documented both hooks and Events that we currently provide. See the updated issue description for the full list.
This was my methodology for finding them:
Comment #4
m.stentaFor context, we are considering adding two new hooks to the
farm_ui_thememodule, which is what prompted this issue.Relevant comments from the PR (https://github.com/farmOS/farmOS/pull/770):
Comment #5
m.stentaOops missed one.
Comment #6
m.stentaThese ones seem like the lowest-hanging fruit (easiest to convert to Events), I think.
This one is modeled after Drupal core's
hook_entity_base_field_info(). I'm hesitant to say we should diverge from that pattern, otherwise we introduce confusion/inconsistency in our DX and documentation (see https://farmos.org/development/module/fields/).Notably, we're waiting for core to refactor how they handle base/bundle fields in #2346347: Finalize API for creating, overriding, and altering code-defined bundle fields.
We have a farmOS tracking issue for that (postponed on that core issue) here: #3194206: Refactor bundle fields when Drupal core supports code-defined bundle fields.
So I'm inclined to say we leave
hook_farm_entity_bundle_field_info()alone, and plan to follow core's pattern. Ideally we'll be able to remove our hook entirely once Drupal gets their solution together. Our hook is really just a "shim" right now.Maybe this one shouldn't even be a hook? Seems like it could be a setting provided by the
farm_updatemodule, that site admins could populate themselves.Although, I guess the main reason we made it a hook is for modules to programmatically add to it.
Making it a config entity could be a nice "feature request" to expand possibilities, but I think we would still need an Event subscriber that allows modules to "alter" the config. So I guess I've come full circle: it needs an Event too. :-)
Comment #7
m.stentaOh I just had an idea...
What if we abstracted BOTH of these hooks (
hook_entity_base_field_info()andhook_farm_entity_bundle_field_info()) into a single farmOSEntityFieldsevent, and recommended that modules use that instead of hooks. Internally we would still use hooks to give Drupal what it expects, but from a farmOS developer's perspective it would all be in one unified place.I guess it's sort of a way of solving the Drupal core + Entity API issues in farmOS. Maybe that's a fool's errand. But it does seem like it would simplify the DX for our users.
Comment #8
paul121 commentedAwesome.
I also like referring to this resource: https://gist.github.com/bojanz/c5fcf5cef22406096588
TLDR;
Most of the time I think we'll want events. But a few of these hooks that are just collecting provided definitions and not altering (like dashboard panes & groups) could potentially use tagged services. A nice write up on them here: https://drupalsun.com/lakshminp/2016/08/17/tagged-services-drupal-8-0
Comment #9
paul121 commentedThis makes sense. I think we would still want separate events to distinguish between base and bundle fields (modules should know which they are providing?) - but yes, we could likely have a single EntityFields event class that could be re-used for both use-cases. And the nice benefit being modules could encapsulate all of this logic into their own, single Event Subscriber class.
Comment #10
m.stentaComment #11
m.stentaI opened this related issue, which IMO we should tackle first: #3516504: Convert all procedural hook implementations to Hook classes
Postponing this issue, but let's review it in more detail to see if there's anything we can work on or plan for in the meantime.
Comment #12
m.stentaComment #13
m.stentaI am proposing that we remove entity events from Log and farmOS in favor of hooks:
Comment #14
m.stentaAfter #3576633: Deprecate and remove asset/organization/quantity entity events is merged, let's dive back into this discussion and update the issue summary to document what hooks and events are present after all the dust settles.
It may make sense to convert some of our hooks to events, but it's clear that the Drupal core hook system isn't going anywhere, so the goal of converting all hooks to events is no longer realistic.