How to register hooks properly?

Hi,
I have a question regarding the registration of hooks. Currently I try to understand how to build apps for nextcloud by doing the app tutorial in the dev documentation. I have looked into other solutions, but it seems that there are many ways. I think the way which is described in the dev doc is not right or at least there are errors in it, because it isn’t working for me.
So my question is: How do i register hooks correctly? The best way for me to understand it, would be a explanation in use of the app-tutorial, because I think I understand the structure of it and got it working for me. An example requirement for a hook in this tutorial would be to delete all notes (use a modified delete method of the noteservice to remove all notes of a specific user), if a user has been deleted… in order to clean the notes for a future user with the same name.
BTW: This example could be a new chapter of the tutorial. It would improve it a little :wink:

janis91

2 Likes

Basically you just add your hook in app.php (or a path that is called from there, like in the activity app):

Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Activity\Hooks', 'deleteUser');

That will be the same as:

\OCA\Activity\Hooks::deleteUser($params);

Then you can use $param['uid'] to continue with your own code

Thank You for your answer. I didn’t know the Util class by now. It’s nice!
But:
As I mentioned, I was following the app tutorial for the so called “ownnotes” app and therefore didn’t have to register any Service in app.php, as it is done in the activity app.
I think the notecontroller and noteservice for example is solved and instantiated automatically.
I think I am a little bit confused by the different approaches, like the directory structure (“lib” directory in activity app vs. “controller”, “service”, “mapper” directories in the tutorial) and the registering of Services with returning of an object, on one hand and the constructor method which is called automatically, on the other hand. For me it seems like it is a lot easier to go the automatic way, like in the tutorial.

Summed up:
I will connect the Hook in my app.php and add a Hooks class to my app. The Hooks class should now call a method in the NoteService class, which is completely the same as in the app-tutorial and has a method for deleting all notes of a specific user.
For me it seems that I have to inject the NoteService class, but if I follow the way of the activity app, I would have to register even the NoteMapper class, in order to register the NoteService calls, so that i can call a method in it. Am I right or do I get something wrong?

1 Like

[quote=“janis91, post:3, topic:2329”]like the directory structure (“lib” directory in activity app vs. “controller”, “service”, “mapper” directories in the tutorial)
[/quote]
That lib/ thing is new and helps a bit to improve performance, otherwise both are basically the same.

[quote=“janis91, post:3, topic:2329”]the registering of Services with returning of an object, on one hand and the constructor method which is called automatically, on the other hand. For me it seems like it is a lot easier to go the automatic way, like in the tutorial.
[/quote]
In this case the activity app is a bit behind, I just never found the time to switch to automatic dependency injection.

Exactly. You just need the hook class, in there you can get your service and run it however you want.

1 Like

Thank You for your answer, I think I am very close to the solution.
Still 2 things:

  1. If the “lib” thing is newer and improves the performance, would you recommend to shift all (controller, db, service and hooks) directories to a directory called “lib”? Will it work out of the box or is does it rely on further configuration?

  2. The big problem with dependency injection is, that the connectHook mechanism expects a static function to be called. How do I call a static function and get my NoteService->method injected from there? Is this even possible? Or how should I handle this? (I think this is the main issue here)

Janis

Here is an email giving you more information

Take a look at this simple class from the mediametadata app

1 Like

Thanks for the mail of the mailing list. It’s pretty useful.
The provided example from the mediametadata app is registering the ImageHooks as a Service for the container. What takes me back to the top of the topic… do I have to register all of my Classes as a Service? Isn’t there a way to stick to dependency injection? It would be a lot easier and also a more modern way, I think. Basically I could register all the Controllers, DBMappers, Services and so on as a Service for the container and use the same (your proposed) way for registration of the hooks. But then I could also completely omit the dependency injection behavior in the other classes.

Sorry maybe i get something wrong…

If you don’t register a class as a service but just let NC fill in the dependencies automatically it’s also called Dependency Injection. Working with a Dependency Injection Container is one way to do it, automatically assembling is another way.

If you want you can register you services in the container, but you don’t have to in the simple cases, which can be resolved automatically. But if you need more logic to inject a service you can still use the container. (e.g. make a decision at run time which class to inject etc)

I think the https://github.com/interfasys/mediametadata/blob/master/lib/Hooks/ImageHooks.php of @oparoz is registered as a service because the automatic dependency assembly can’t be used in this specific case. The first parameter isn’t available as a service itself, so the automatic system can’t find it.

Refs https://docs.nextcloud.com/server/9/developer_manual/app/container.html#use-automatic-dependency-assembly-recommended

I hope this explains it a bit more, and that I don’t make you more confused :wink:

TL:DR you can use automatic assembling in the simple cases, but you don’t have too. Use DI (with or without container) in these cases https://docs.nextcloud.com/server/9/developer_manual/app/container.html#which-classes-should-be-added

1 Like

I hope this explains it a bit more, and that I don’t make you more confused

Not at all. This was really helpful! Thanks. I will do it like proposed and will come back to this topic as soon as I got a working solution, such that everyone else will have an example for the future.

Thanks to you all!

The result for the OwnNotes example in the tutorial, which is already successfully tested:

Register the hooks in Application.php.
and
Create the hooks class and inject the service respectively the method of the serivce.

Thank You for your help!

1 Like