I’ve also tried a Drupal Webhooks module but so far have not gotten it to work. Webhooks | Drupal.org
I got the following in error logs after enabling and creating a new log. Are there routing differences between Standard Drupal and farmOS?
Symfony\Component\Routing\Exception\RouteNotFoundException: Route "entity.log_type.canonical" does not exist. in Drupal\Core\Routing\RouteProvider->getRouteByName() (line 206 of /opt/drupal/web/core/lib/Drupal/Core/Routing/RouteProvider.php).
Symfony\Component\Routing\Exception\RouteNotFoundException: Route "entity.log_type.canonical" does not exist. in Drupal\Core\Routing\RouteProvider->getRouteByName() (line 206 of /opt/drupal/web/core/lib/Drupal/Core/Routing/RouteProvider.php).
Any modules for 2.x in development for dispatching events to external applications?
Not that I’m aware of! Other than the simple sensor notifications features for sending emails if a threshold is crossed… but that’s pretty specific for that purpose.
I got the following in error logs after enabling and creating a new log. Are there routing differences between Standard Drupal and farmOS?
Those may be a bug with the Webhook module itself. It seems to be assuming that a certain route is defined by Log, which isn’t… ? Not sure…
Quite possibly, after a good bit of searching yesterday, there does not seem to be many options for this sort of function. I did however discover that Drupal Core includes a http client based on Guzzle, so its probably time I brush up on a little PHP anyway. https://www.drupal.org/node/1862446
You don’t need any special modules to trigger simple code to run when entities are added/updated/deleted… You can do it easily in a simple custom module. Drupal’s hook system makes it super easy!
The way hooks work is… you just create a file called [mymodule].module (alongside [mymodule].info.yml) and add functions to it. These functions are named in a very specific way so that Drupal will automatically run them when necessary.
For example, if I wanted to run some code whenever a log is updated, in a module called mymodule, it would look like this:
/**
* Implements hook_ENTITY_TYPE_update().
*/
function mymodule_log_update(EntityInterface $entity) {
// My PHP code...
// This will run whenever a log is updated.
// $entity is the log.
}
The naming of the function is critical for this to work. In this case, you take the name of the hook (eg: hook_ENTITY_TYPE_update()), replace hook with your module name (mymodule), and ENTITY_TYPE with the entity type (log). Result: mymodule_log_update().
Whenever a log entity is updated, Drupal basically says “hey all you modules - anyone got a function named [modulename]_log_update()? yea? alright let’s go!” and it runs it.
That’s the quick intro - but hopefully that’s enough to get you going!
Worth noting: hooks are the historical way to do these kinds of things in Drupal… but they are not the only way. With D8+, a lot of things are moving towards using event subscribers instead of hooks. Event subscribers are OO (object oriented), whereas hooks are more traditional procedural functions.
FWIW farmOS core tries to use event subscribers wherever possible because everyone is trying to move towards more OO in Drupal code. But for custom modules, hooks are the most dead-simple way to do it, and I’d probably recommend starting there.
Really is! Obviously needs a little more to catch exceptions, authentication and filter just the log types that I want. Maybe eventually a UI to configure these options too.
<?php
/**
* @file
* Contains farm_events_http.module.
*/
use Drupal\Core\Entity\EntityInterface;
/**
* Implements hook_ENTITY_TYPE_update().
*/
function farm_events_http_log_update(EntityInterface $entity) {
$log = $entity->toArray();
//Create httpClient.
$client = \Drupal::httpClient();
//Sending POST Request with $json_data to external server
$request = $client->post('http://192.168.1.7:1880/farmos/webhook', [ 'json' => $log]);
//Getting Response after JSON Decode.
$response = json_decode($request->getBody());
I think this thread may be a more appropriate home for that conversation.
I have been looking at a few already and borrowed @paul121’s farm REI example for my withdrawal module, although I’ve used the hooks method so far in this project.
I’m currently trying to figure out how to add a configuration page and have been looking at form API examples and adding menu items.
Great! If this will be a general notifications settings form, then it probably makes sense to add it as a tab under the /farm/settings path (alongside “Farm Info”, “Modules”, etc).
The Quantity settings might be a good example to work from since it’s simple.
There are a couple of pieces to this that all work together:
The quantity.links.task.yml file which adds the “Quantity” tab itself (pointed to the route defined in quantity.routing.yml), under the farm_settings.settings_page base route.
The ConfigFormBase class is basically just a slightly more specialized extension of the general FormBase class, specifically for config forms like this. It adds the config.factory service via dependency injection so you can use it in your submit() method to save Drupal config settings.
Still plenty to work out and do but at least now I don’t need to hard code settings anymore. The basic mechanics are working for using ntfy.sh and Node-Red as servers I may add some more in future.
I wonder if the Node-Red/WebHook/MQTT case might be better described by the term “events” instead of “notifications”. It feels like the “events” case probably belongs in its own module compared with the Ntfy “notifications” case.
Events: Tell some other server that some data has changed so it can run its own code - possibly making farmOS API calls to get more data and/or storing/maintaining its own state somewhere else.
Notifications: Tell/remind a user of farmOS about something on the farmOS server. Presumably, farmOS should make the decision about which user to tell, when to tell them, and what to say.
2022-05-19T13:41"Example Farm @Alice - New activity log assigned: May 20th - Mow back 40"
2022-05-19T17:22"Example Farm @Alice - Updated activity log: May 24th - Mow back 40"
2022-05-23T15:00"Example Farm @Alice - Upcoming activity log: May 24th - Mow back 40"
2022-05-24T16:00"Example Farm @Alice - Overdue activity log: May 24th - Mow back 40"
Good feedback @Symbioquine! I would agree that “events” might be better for general event propagation to external APIs (which then handle the “notification” aspect specifically).
This is always one of the challenges with Drupal module development… the balance between general and specific. Sometimes you need multiple modules to achieve a specific goal - building up from general to specific!
Aside from those bigger points, I skimmed the code and have a few specific suggestions, if you are open to them @Farmer-Ed…
First, I notice that it implements hook_log_update() - which is fired when logs are updated. You probably also want to implement hook_log_insert() (fires when logs are created), and hook_log_delete() (fires when logs are deleted).
PHP CodeSniffer is a great way to find and fix coding standards issues! If you are using the dev environment already then it’s pretty easy to use: Coding standards | farmOS
Hope that helps! Keep up the good work @Farmer-Ed !
Thanks for taking the time for that detailed critique @mstenta.
I don’t even know where the farm_medical dependency came from, obviously a cut and paste from another project
I will take those recommendations on board.
on the hook_log_update() or hook_log_insert() I was thinking about this and unsure whether or not an update to a log also justified a notification (or event), had contemplated making it an option. Just glad at the moment it fires as expected
@mstenta I was looking at the option of plugins that you suggested on the call and love the idea, but suspect it could be beyond my current abilities, have you an example of its implementation? I was thinking of adding additional server types later including Google calendar (although I’ve left that out for now due to the authentication complexity of the API and the fact that I have it working well in Node-Red anyway, but perhaps it may be more worthy of its own module and settings panel in the future).
I want to add a Boolean switch to logs to be able to turn on/off if they should be notifiable events. The switch appears in the logs but its value seems to be always null
/**
* Implements hook_entity_base_field_info().
* NOTE: Replace 'mymodule' with the module name.
*/
function farm_notifications_entity_base_field_info(EntityTypeInterface $entity_type) {
$fields = [];
// 'log' specifies the entity type to apply to.
if ($entity_type->id() == 'log') {
// Options for the new field. See Field options below.
$options = [
'type' => 'boolean',
'label' => t('Notify'),
'description' => t('Send Notifications for this log.'),
'settings' => [
'format' => 'default',
'format_custom_false' => '',
'format_custom_true' => '',
],
'weight' => [
'form' => 10,
'view' => 10,
],
];
// NOTE: Replace 'myfield' with the internal name of the field.
$fields['farm_notification_notify'] = \Drupal::service('farm_field.factory')->baseFieldDefinition($options);
}
return $fields;
}
I’ve tried various combinations of changing the format options under settings but don’t think that’s the issue. Perhaps an initial default value is needed for booleans?
Edit: setting an initial value does seem to fix it, I’ll do a bit more testing later though.
Another Edit:
Maybe Radio style options would be better to trigger events based on status?
farmfield.factory could do with a little more documentation.
I wouldn’t worry too much about this right now. It can be broken out into plugins (or some other mechanism) pretty easily in the future. I’d probably just open a todo issue as a placeholder to start thinking about it. This submodule of the “Examples for Developers” module might be helpful (but there may be other/simpler ways to accomplish the same thing): modules/plugin_type_example · 3.x · project / examples · GitLab
(Even if you did, it is a very deep-dive - and largely extends from the core Drupal field system, which itself could probably be better documented. IMO we should only document the farmOS-specific bits on top of that, and improve the Drupal documentation upstream as needed.)