We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 41406 ☆ A M B ☆
    • 30 Posts
    OK, so I've been working on a 'recent activity' component recently, and while there's a few ways to aggregate all the relevant data across a site, I keep coming back to a custom event with a plugin to handle the logging of actions into a new db table.

    I post my thoughts and vague plans here in the hope of some external opinion and critique before i dedicate myself to building the component properly. Please let me know your thoughts, suggestions or ridicule...

    The Event
        @name OnUserAction
        @service 6
        @groupname Users
    

    In order to handle aggregation of input from various (futureproofed) sources, the event accepts an array of predefined yet flexible parameters:
        @param string action - Name of action (past-tense, lowercase, english) [required]
        @param string object - Name of object action was performed on [optional]
        @param int    user   - ID of user committing the action [optional - defaults to session user id]
        @param string f1..f5 - 5 free text fields that can be used to store other data around the action to allow better filtering of records on output
    


    The main Plugin
    Bound to the new event is the main workhorse plugin. It will take the parameters supplied to the event and create an object describing the action
    class modUserAction extends xPDOSimpleObject
        var int     user              - The id of the user who commited the action
        var string  action          - Verb describing the action
        var string  object          - Object action was performed on
        var int     timestamp     - Time action occurred
        var str     f1..f5             - Free text fields storing extra data. Will vary by action type.
    


    The core trigger Plugin
    A secondary plugin bound to various system events to invoke an OnUserAction event when resources are published or updated, when users register or update their profile etc.

    The extensible bit
    The idea behind setting things up this way is that future 3rd party components would have the option to include a call to the event, participating in the tracking process.


    So yeah... that took far longer to articulate in a vaguely coherent manner than i expected, but I think it has the potential to be a valuable addition to the core process. Any thoughts? [ed. note: alanpich last edited this post 13 years, 11 months ago.]
      • 28042 ☆ A M B ☆
      • 24,524 Posts
      Have you looked at the "Manager Actions" report generating code? You might be able to modify some of its functions.
        Studying MODX in the desert - http://sottwell.com
        Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
        Join the Slack Community - http://modx.org
        • 41406 ☆ A M B ☆
        • 30 Posts
        You might be onto a winner there! Hadn't looked into the mgr log before n kinda naively assumed it was doing the aggregation at output time. looks very sililar to my proposed folds so almost certainly could borrow some code. Good shout smiley

        Now just gotta convince other authors to include the event calls in future versions of relevant components (e.g. quip)
          • 28042 ☆ A M B ☆
          • 24,524 Posts
          Actually it's in core/model/modx/modx.class.php:

              /**
               * Logs a manager action.
               * 
               * @param string $action The action to pull from the lexicon module.
               * @param string $class_key The class key that the action is being performed on.
               * @param mixed $item The primary key id or array of keys to grab the object with.
               * @return modManagerLog The newly created modManagerLog object.
               */
              public function logManagerAction($action, $class_key, $item) {
                  $userId = 0;
                  if ($this->user instanceof modUser) {
                      $userId = $this->user->get('id');
                  }
                  $ml = $this->newObject('modManagerLog');
                  $ml->set('user', (integer) $userId);
                  $ml->set('occurred', strftime('%Y-%m-%d %H:%M:%S'));
                  $ml->set('action', empty($action) ? 'unknown' : $action);
                  $ml->set('classKey', empty($class_key) ? 'unknown' : $class_key);
                  $ml->set('item', empty($item) ? 'unknown' : $item);
          
                  if (!$ml->save()) {
                      $this->log(modX::LOG_LEVEL_ERROR, $this->lexicon('manager_log_err_save'));
                      return null;
                  }
                  return $ml;
              }
          


          Shouldn't take much to have it create a modUserLog object instead of modManagerLog; you would need to establish the moduserlog configuration; modmanagerlog.class.php and modmanagerlog.map.inc.php are in core/model/modx/mysql/ along with a whole bunch of other class and map files; they should give you the idea of how to set up a custom object.
            Studying MODX in the desert - http://sottwell.com
            Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
            Join the Slack Community - http://modx.org