We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 49407
    • 159 Posts
    I recently installed the ClassExtender extra in hopes that I could somehow use it to add a "sendNotification" method to modUser objects. After reading the tutorial on Bob's Guides, I'm not sure that's what I need.

    Is there a way to do something like $xpdo->loadClass('customUser', '/path/to/methods/custom_user.methods.php'); where that class extends the modUser class by adding my own methods?

    I read the documentation on $xpdo->loadClass but it seems specific to the database/model side rather than the methods side of it. I really don't need to extend the database, I just want to add a method for sending user notifications.

    This question has been answered by BobRay. See the first response.

      • 49407
      • 159 Posts
      There has to be a way to extend a class without adding a new database table. I don't need a new database table. I just need to add a method. I obviously don't want to edit the core files. Everything I have read thus far talks strictly about the model. I already have the model.

      I know how to do this with PHP outside of Modx, but my end goal is to be able to do this:

      $user = $modx->getObject('customUser', $userID);
      
      $message = 'Someone viewed your profile!';
      
      $user->sendNotification( 'online', $message );
      $user->sendNotification( 'email', $message );
      $user->sendNotification( 'mobileApp', $message );
      $user->sendNotification( 'textMsg', $message );


      So, where should I even start?
        • 3749
        • 24,544 Posts
        If you don't want to add a custom table (though that's pretty easy with ClassExtender), you can re-purpose one of the existing User Profile fields (e.g. fax or mobilephone -- be careful of the types, you don't want to use a boolean field), or you can use the extended field of the profile.

        Here's how to do the extended field. Be aware that it's somewhat cumbersome and slow to retrieve or search for values in the extended field. Re-purposing another field is much easier and faster.

        $profile = $modx->getObject('modUserProfile', array('internalKey' => $userID));
        if ($profile) {
            $extended = $profile->get('extended');
            $extended['field1'] = 'someValue';
            $extended['field2'] = 'someOtherValue';
            // etc.
            $profile->set('extended', $extended);
            $profile->save();
        
        }


        BTW, do you really want to send four messages to the user?

        [upddate] After re-reading your posts, I don't think you need to extend the user at all unless you need to store the user's preferred contact method. You can just put a snippet in the template of the user profile pages that sends the message. You could also use a plugin attached to something like OnWebPageComplete, but I think the snippet would be much easier. [ed. note: BobRay last edited this post 11 years ago.]
          Did I help you? Buy me a beer
          Get my Book: MODX:The Official Guide
          MODX info for everyone: http://bobsguides.com/modx.html
          My MODX Extras
          Bob's Guides is now hosted at A2 MODX Hosting
          • 49407
          • 159 Posts
          Quote from: BobRay at Sep 25, 2015, 02:37 AM

          BTW, do you really want to send four messages to the user?

          No, I was just giving four examples.

          Quote from: BobRay at Sep 25, 2015, 02:37 AM
          [upddate] After re-reading your posts, I don't think you need to extend the user at all unless you need to store the user's preferred contact method. You can just put a snippet in the template of the user profile pages that sends the message. You could also use a plugin attached to something like OnWebPageComplete, but I think the snippet would be much easier.

          If I were adding a method or extending a class, normally, I would write something like this...

          <?php
          class ExtendedUserMethods extends modUser {
              public function __construct() { 
                  parent::__construct(); 
              } 
          
              private function sendNotification($platform, $message) {
                  // The code that sends the notification based on the user's preferred method
              }
          }


          So, if I simply want to extend the modUser with a single method, without doing anything else, where do I put my new extendedusermethods.class.php file? Where do I tell modx about it so that I can access it by creating a user object with $user = getObject('ExtendedUserMethods', $userID); $user->sendNotification('platform', $message);?
            • 3749
            • 24,544 Posts
            I still don't understand why you need to extend modUser. Other extras also extend modUser, so there could be conflicts and it doesn't really gain you anything, if I'm understanding your use case. You'll have to write custom code to modify the class_key in the user object and you'll have to do that retroactively for any existing users. Any extra code that looks specifically at the class_key will ignore your users.

            Even if you extend modUser, you'll still need a custom snippet or two to save the data and retrieve it (assuming that there's data to be saved).

            Anywhere you have the user ID (which you're going to need anyway), you can write a function or method to notify the user without messing with the user class.
              Did I help you? Buy me a beer
              Get my Book: MODX:The Official Guide
              MODX info for everyone: http://bobsguides.com/modx.html
              My MODX Extras
              Bob's Guides is now hosted at A2 MODX Hosting
              • 49407
              • 159 Posts
              Quote from: BobRay at Sep 25, 2015, 11:45 PM
              I still don't understand why you need to extend modUser. Other extras also extend modUser, so there could be conflicts and it doesn't really gain you anything, if I'm understanding your use case. You'll have to write custom code to modify the class_key in the user object and you'll have to do that retroactively for any existing users. Any extra code that looks specifically at the class_key will ignore your users.

              Even if you extend modUser, you'll still need a custom snippet or two to save the data and retrieve it (assuming that there's data to be saved).

              Anywhere you have the user ID (which you're going to need anyway), you can write a function or method to notify the user without messing with the user class.

              Well, I'm not sure you understand the usage cases. When put to use it will be intuitive, just like $user->changePassword();. I don't put snippets or chunks into my resource contents, and I don't put functions that should be methods into snippets, it's bad practice.

              I just want to know how to get it done so I can move on to the next task. This would be an excellent core feature, but it's not, so I'm making it like one.
                • 49407
                • 159 Posts
                Quote from: BobRay at Sep 25, 2015, 11:45 PM
                Even if you extend modUser, you'll still need a custom snippet or two to save the data and retrieve it (assuming that there's data to be saved).

                Why would I need outside snippets? The modUser class already saves and retrieve data internally. I see no reason why my method can't save and read data, it's an extension of modUser which is an extension of xPDO.

                EDIT: modUser parents < \modPrincipal < \xPDOSimpleObject < \xPDOObject
                  • 3749
                  • 24,544 Posts
                  You haven't said what data you'll be storing or where, but it's much more likely that you'll be storing it in the modUserProfile object. For either object, the save method will only save fields it knows about. If you're not using those, you'll need to modify the table (highly not recommended), or create a custom table.

                  What I'm trying to say (if I'm understanding you) is that at some point you want to send the user a notification. As long as you have the user ID at that point, it's trivially easy to just do it. Extending a MODX object to do it would be non-trivial, much more work, and overkill imo, though if you want to do it that way it's certainly possible.

                  https://rtfm.modx.com/revolution/2.x/developing-in-modx/advanced-development/extending-moduser

                  If you're worried about re-using the code, you can put it in a snippet and call it with $modx->runSnippet(), or put it in a class file, include it, and instantiate it in your code.
                    Did I help you? Buy me a beer
                    Get my Book: MODX:The Official Guide
                    MODX info for everyone: http://bobsguides.com/modx.html
                    My MODX Extras
                    Bob's Guides is now hosted at A2 MODX Hosting
                    • 49407
                    • 159 Posts
                    Quote from: BobRay at Sep 26, 2015, 12:18 PM
                    You haven't said what data you'll be storing or where, but it's much more likely that you'll be storing it in the modUserProfile object. For either object, the save method will only save fields it knows about. If you're not using those, you'll need to modify the table (highly not recommended), or create a custom table.

                    What I'm trying to say (if I'm understanding you) is that at some point you want to send the user a notification. As long as you have the user ID at that point, it's trivially easy to just do it. Extending a MODX object to do it would be non-trivial, much more work, and overkill imo, though if you want to do it that way it's certainly possible.

                    https://rtfm.modx.com/revolution/2.x/developing-in-modx/advanced-development/extending-moduser

                    If you're worried about re-using the code, you can put it in a snippet and call it with $modx->runSnippet(), or put it in a class file, include it, and instantiate it in your code.

                    I have a class (UserSettings) with extended user setting such as privacy, notifications, etc.. There is also a built in modUserMessage class. The sendNotification method will use the UserSettings class to evaluate how to notify the user. If the user has chosen 'online' or 'mobile' as an option then modUserMessage will be used to send the notification via the mobile app or online, otherwise it will be an email notification/text. The sendNotification method would also access a separate class "Notification" that is not part of my ExtUser class.

                    Ideally I would like to be able to have the user object contain a method that would allow the programmer the ability to $user->sendNotification( $messageType ) or $user->sendNotification( $messageType, $relatedUserID ), so that there is no need to perform an include every time you already have the user object available. It's much better in practice to do this and it is also more intuitive whilst coding. The sendNotification method will only be saving modUserMessage object data, which the model already exists for.

                    $targetUser = $modx->getObject( 'ExtUser', $profileID );
                    $profile = $targetUser->getOne('profile');
                    $browsingUser = $modx->getUser();
                    $targetUser->sendNotification( 'profile_view', $browsingUser->get('id') ); // the "profile_view" verbatim can be easily changed in the data field
                    // it's also easy to add, to the method's switch, another case, "profile_like", or another "profile_follow"
                    // also, since we are using a method we don't have to get the browsing user's profile here, because the method gets it and uses the "fullname" field
                    // all we need to do is specify the type of notification and the user it is in reference to
                    // if this is a system message from an administrator it can be sent without specifying the second parameter
                    


                    As opposed to...

                    $targetUser = $modx->getUser( $profileID );
                    $profile = $targetUser->getOne('profile');
                    $browsingUser = $modx->getUser();
                    // doing other stuff anyway like displaying the profile, so I already have the targetUser object
                    // wait, let's not use a method, let's annoy the coder and make them write four extra lines every time they want to add notifications to an event!
                    $message = 'Someone viewed your profile!'; // Now we have to find this to change the verbatim rather than change a field in the data
                    $arrayOfParameters['message'] = $message;
                    $arrayOfParameters['to'] = $targetUser->get('id');
                    $arrayOfParameters['from'] = $browsingUser->get('id');
                    
                    $modx->runSnippet( 'sendNotification', $arrayOfParameters );
                    


                    In conclusion, I do need another data table that will specify the message types and their verbatim. A simple table with three columns, id(int)[auto_increment], key(varchar)[unique], value(tinytext)[not_null]. At the time I started engineering this feature I didn't account for this. I apologize.

                    Now, the ExtUser class will not need any data that isn't already in the UserSetting or Profile data. there will need to be an additional class called "Notification", but the Notification class should not extend modUser, rather, the Notification class will be utilized by the ExtUser class methods. Do you follow me? Can I set this up within modx? Can I access Notification class from within ExtUser methods just like Profile is accessed from modUser methods?
                      • 3749
                      • 24,544 Posts
                      I think I do follow you (more or less) and I see why you want a user class method. I don't think I'd do it that way, but I can see the attraction of it. I don't understand the purpose of the separate Notification class so I can't really answer the question, though you can do just about anything with MODX.

                      If I'm understanding you, what you're planning to put in the Notification table would typically be put in chunks, unless there will be a whole lot of records. This makes it much easier to edit and you can put placeholders in the chunks for things like username, etc.

                      SomeChunk content:

                      <p>Hello [[+username]] here is a notification (etc.)</p>


                      Then your code can do this:

                      $fields = array(
                         'username' => $modx->user->get('username'),
                      );
                      
                      $text = $modx->getChunk('SomeChunk', $fields);
                      


                      getChunk() will replace the placeholders for you.

                      If the chunks are named for the notification methods, it's easy to pull in the ones you need.




                        Did I help you? Buy me a beer
                        Get my Book: MODX:The Official Guide
                        MODX info for everyone: http://bobsguides.com/modx.html
                        My MODX Extras
                        Bob's Guides is now hosted at A2 MODX Hosting