Is it possible to retrieve a list of all methods added to a class?

I was reading about Magic Methods in Plugin Quick-Start Guide, and I was wondering, is there a way to see al the methods that have been "tacked" to a class? A simple get_class_methods() doesn't work, as these new methods are not shown.

vanilla magic methods refer to the use of __call, what is passed. In PHP it refers tot he special method used for overloading __call, __callStatic, __get, __set, __isset, __unset, (the latter four are used on 'magic' properties).

Argh! I was so close! I implemented a method that could return a list of the Magic Methods added to a class, but the list is declared as "private", therefore I can't access it. If nothing else, I learned that such Magic Methods have some important limitations, compared to "normal", declared methods.

I know. In my case, I'd need to access a private property Gdn_PluginManager->_NewMethodCollection to retrieve all the Magic Methods associated to a class. My target would be to loop through all of them and call them one by one.

What I'm trying to achieve is a functionality similar to a global "Cron", where a plugin can declare a Cron method (e.g. Cron_MyPlugin_Create()) and have it called regularly (this in its simplest version, obviously there's much more that can be done from there).

Unfortunately, the only way I managed to implement it successfully so far has been by hacking class Gdn_PluginManager and exposing property _NewMethodCollection, either by declaring it public or by using a "Get" method.

Of course, I don't want to rely on such a hack, as, if I really had to modify the Core, it would be much cleaner to simply implement a GetClassNewMethods method straight into Gdn_PluginManager class.

Thanks again. I'm not sure I understand the $this->EventArguments['UsefulStuff']=$UsefulStuff part. What I actually want to do is to allow my Cron plugin to call other plugins methods, which are stored in a list somewhere. This way, if a new plugin would need to run something periodically, it will just have to register itself with the Cron Plugin, which, in turn, will call the callback method at each execution.

I reckon it would be done with Events too: by firing a "CronJob" event, any 3rd party plugin would just have to implement a handler and do some stuff in it. However, this means that all Cron Event Handlers will run unconditionally. Forcing a plugin to register a method would allow some sort of control over the Cron Events (for example, some could be enabled or disabled, depending on the circumstances). This is how I implemented it at the moment (I must say it was easier than I thought, even considering that I took the "wrong route" multiple times).

In short, I see there are many ways of doing it, and there isn't an "absolutely better" way.

no it is just anything you want to pass through the $Args. It also has the original sender object, which in this case you be the CronJobsPlugin instance. So you could have public methods and properties that they could use.

@x00: I'm sorry, but I'm not sure I follow you. Let me see if I understand.

1- CronPlugin would fire an event, such as RegisterCron.
2- Other plugins that would like to be registered a method to run during a Cron execution, would implement MyPlugin_RegisterCron_Handler. Such handler would receive some information needed by the client plugin to register (i.e. the Sender, which is my CronPlugin and, eventually, other arguments).
3- Client plugin uses the information in the handler to register itself.
4- CronPlugin will now have a set of methods to call during Cron execution.

The above means that, if a 3rd party plugin is installed, but CronPlugin is not, its method MyPlugin_RegisterCron_Handler is not getting called, but the plugin works anyway.

MyPlugin_RegisterCron_Handler should be CronPlugin_RegisterCron_Handler

what you are actually doing is defining what the cron entails, but since it is a cron, you need to pass the necessary info. Say for instance a request is your basic unit, you would need to pass the algorithm/formula that determines it is time to perform that task (it can be quite intelligent and factor in many things). It can also help if there was a model reference in CronPlugin, which can be passed to the cron method provide a way of storing values to check later.

You also need the payload which is the task itself. This can be passed as an object method, a static method, or a standalone function.

So you could have an convenience AddTask method perhaps. It could add to an indexed collection(s) of task and the cron formula.

then your CronPlugin will be checking every basic unit (such as every request), loop through the task to see if anything need to be performed and if so calling the method.

you can also specify what other plugins are required, when you create a plugin in the PluginInfo. It shouldn't enable through the dashboard otherwise.

If you want a proper cron, i.e. somethign that is running the background regardless of the requests, then you need to be able to interface with and support such infrastructure, it is a little bit more tricky if you are hoping to have a distributed solution.

I think I understand now. The code you wrote goes into the 3rd party plugin, right? So, workflow would be the following:
1- Cron Plugin fire RegisterCron event.
2- Client Plugin implements a handler to register itself. Here it can pass the method to execute and, optionally, another method that Cron Plugin will run to determine if it's time to execute the first or not.
3- Cron Plugin will run the Execute method, loop through all the registered plugins, executes the "should I run it?" method of each client plugin (if it exists) and, eventually, run the Cron method.

Did I get it right, finally?

Regarding the proper Cron, I could use a hybrid solution such as the one implemented in Drupal: expose a menu entry, accessible via URL, which would fire the Cron sequence. Such menu entry would be secured, so that only localhost could call it (this is to prevent DDoS attacks). Additionally, some throttling mechanism could be implemented as well, but we're going into a lot of detail now.

@x00: Thanks again for the example. However, I decided to take a simpler route for the moment. The Cron Plugin will simply fire all registered Cron tasks at every run. User will just have to schedule a call to the appropriate menu item (e.g. /cronplugin/execute) and that's it.
I'm at the very beginning of designing it and I'm not even using a Model yet, just an associative array. Plenty of refactoring to be done, but, right now, it actually works!

Thank you very much for your (late night) help. GMT time zone here, it was late for me too.

It's a good idea to have something persistent, although the "Unregister" phase would have to be handled as well. For simplicity, I simply allow plugin to register themselves at runtime, it's anyway a fairly cheap operation (an "add" to an array). This way, if client plugin is active, its Cron will be called. If not, it will not be called. Easy.

x00 said:
well the register could be per prequest, it doesn't mean you are storing the register.

However the task and the taskcondition may need some persistent data to work.

Say you only want to cron on the 5 day of the month, but you don't want to be doing the task over over on the 5th you have to make a record the task has been performed.

@x00: you're spot on, the ability of deciding what to run and when would be great. However, for the moment, I won't let my CronPlugin handle this yet, it will be the next version. Every Cron Run will fire each and every registered event, every time, and it will be up to the plugin to decide what to do. After all, there aren't plugins using it yet, therefore there's no point in adding features before the core functionality has been tested.