We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 14877
    • 110 Posts
    [It probably goes without saying, but: If this is the wrong forum, please move this thread.]

    Discussion in another thread I started prompted this post. This topic is about coding Snippets and Plugins — not what any particular instance does, but "coding". I’d appreciate any constructive criticism of these comments, especially if any of my assumptions are wrong. There is some of my programming philosophy inherent in these comments (surprise, surprise!). Please note that I am not involved in developing anything for distribution with/for MODx (that may change when I have enough experience using MODx) — this thread is from the perspective of someone creating a web site using MODx.

    ===

    1. Global variables are bad.
    2. Parameters are passed for a reason.
    3. Snippets and Plugins serve a purpose similar to a "function", "subroutine", "module" or whatever terminology is appropriate.

    In an ideal world, the code in a Snippet or Plugin would be isolated. By the way, in the rest of this post, I will use the phrase "the code" to mean "a snippet or plugin". It would receive its input via parameters and would be able to cause effects only by using well-documented objects (i.e. their methods and public properties). MODx helps in this regard by using the prefix, "modx" to distinguish its objects. That means, of course, that no snippet or plugin should name a variable "mod...". Even if the code were somehow isolated so it couldn’t cause side-effects, the name would be confusing to anyone reading the code (including the author at a later date).

    So, the code should start out by accessing whatever parameters are passed to it. This means something like

    $myVar = $modx->getOption('some_parm', $scriptProperties, '');


    Immediately there is an issue: What is $scriptProperties? (That’s a rhetorical question, please don’t answer it!).

    It is a variable whose name does not start with the "mod" prefix, but it is "being passed" to the code. Are there other global variables that are available to the code? Is there a list of them in the documentation? In the other thread I mentioned earlier, a responder suggested the first statement in the particular code I was discussing (an event handler) should perhaps be

    $profile = $user->getOne('Profile');


    What’s this "$user"? (Less of a rhetorical question!). If I was unaware that "$user" was some global variable (I was and am still fuzzy about this as I cannot find any documentation about it), I might inadvertently have used that variable name in the code. It is after all, a nice meaningful name and the whole "system" is dealing with "users" of our web site. So I assign a value to "$user", my code appears to run alright, but some strange things start to happen...

    What about "$profile"? I’ve use that as a variable name in my code. Is it a global variable as well?

    So I woke up much earlier than usual this morning thinking about MODx (obviously my subconscious was having a field day mulling over this topic). Should "the code" only use variable names that start with some prefix? For example, I suspect a variable called "$myvarUser" would be safe. Should I be trying to encapsulate all of the code in a function so variables have a local scope? That way, the event handler I referred to earlier might look like

    function myOnUserActivate($user) {
        /* the code */
        return 0;
    }
    myOnUserActivate($modx->getOption('user', $scriptProperties, ''));


    So: Comments? Suggestions? Rude remarks?
      __________________
      JRG
      • 3749
      • 24,544 Posts
      I’m not sure if this qualifies as a rude remark or not (and I don’t mean it in a critical way), but have you considered actually looking at the MODx core code to see how it works before suggesting that the design is flawed? wink

      Honestly, I don’t think that anything you’re discussing qualifies as a global variable. If you have a good debugger, write yourself a small snippet with no properties and step thought its code while it’s running in MODx. See how many MODx global variables are available. You’ll find the $modx object (a subclass of the xPDO object), which is explicitly passed to "the code" of a snippet (along with the $scriptProperties array, which should be empty if the snippet has no properties).

      The current resource is a member of the $modx object ($modx->resource). The current user is another ($modx->user). Those two objects each represent a row in a table of the MODx database (as does the user Profile, which is a member of the $user object). Information about the resource, the user, or the user profile, is accessed through the various object’s get() and set() methods. So to get the Profile of the current user in a snippet:

      $profile = $modx->user->getOne('Profile');


      In a plugin, the $modx object is available, plus the small number of variables passed in the $modx object’s invokeEvent() method - usually just one or two, sometimes none.

      I hope this makes sense. smiley




        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
        • 14877
        • 110 Posts
        Hi Bob, it certainly makes sense in a theoretical way, but lets take the OnUserActivate event. When the plugin is invoked,

        $profile = $modx->user->getOne('Profile');


        is of no use whatsoever. The "user" is the "anonymous" user. So lets turn to the "passed parameter" (which was my original question in my original post which led me to start this one). That question was, more or less, "Using the passed parameter, how do I access the "username" and user profile information for the user who "has just been activated?" [For what it is worth, after the plugin returns, whether the plugin does anything or not, the user will be put into a logged-in state.]

        The documentation for the Login extra (which I’m using) states: "ConfirmRegister also fires the OnUserActivate plugin event after the User is activated, and passes in a ’user’ parameter, which contains the newly-activated modUser object."

        I, perhaps not understanding how the object-oriented PHP code works, or perhaps what some things represent in MODx, went through the MODx documentation and found that modUser::getSettings: "Gets all user settings in array format." So I thought,

        $actUser = $modx->getOption('user', $scriptProperties, '');
        $formPlaceHolderPairs = $actUser->getSettings();


        Would do what I wanted. That’s not the case, which is why I turned to the forums in the first place. My post was called "Processing parameter(s) passed to plugin". What I was told was: "in the plugin, the user object is available as $user and $scriptProperties is not available.".

        NOW I started to question how the architecture was set up (or perhaps documented): What is $user? The documentation doesn’t say $scriptProperties is not available. What it says is: "Plugins are similar to snippets in that they are snippets of code that have access to the MODx API - however the big difference is that Plugins are associated with specific System Events." Now the examples given only access data through the modx object, so they certainly implied that parameters should be accessed the same way. The documentation on properties says: "You can also get a snippet property with $modx->getOption() like this:" (and gives an example).

        So, this technically doesn’t qualify as looking at the "core code", but I did look at the ConfirmRegister snippet code. After a bit of code that prevents the snippet doing any further processing if it "Could not save activated user", we have the following:

        /* invoke OnUserActivate event */
        $modx->invokeEvent('OnUserActivate',array(
            'user' => &$user,
        ));


        I think that would suggest that a parameter called "user" is being passed using a "modx" mechanism.

        I thought (and still do) that what I’ve read about the MODx architecture makes it the kind of CMS (or CMS Framework) that I want to use; but I do start to question things when I cannot find out how to use the documented parameter-passing mechanism — especially when I do dig enough to see the above code is how the plugin in question is being invoked. That code seems to me (a retired, old-fashioned procedural language programmer) to say:


        • Call the "invokeEvent" method of the "modx" object
        • Tell it to fire the "OnUserActivate" event
        • Pass the invoked event handler(s) a parameter array with the parameter "user" and the value "$user" being passed by reference

        It certainly doesn’t suggest accessing the variable "$user" (it is a variable, though you can call it an object handle, or whatever you want in an OOP environment). Presumably other event handlers may get passed other parameters. Perhaps none of the MODx code relies on any of its variables being left untouched after a snippet or plugin has been invoked. I don’t know. I do know that regardless of whether the variable is "global" by a strict PHP definition, if some code is to be invoked in isolation, it shouldn’t be accessing variables not defined in its code except via a parameter passing mechanism (the modx object is one such mechanism).

        In my opinion it is not inappropriate to raise such an issue or question whether relying on such accesses is violating architectural integrity — without a prerequisite being to read all the code. If one reads all the code (probably close to impossible, especially if one strives to understand it), then one has no need to ask questions as one will know the answers.

        It’s really no different than questioning the performance of the system (which people do). I’ve noticed the performance issue. I understand how such problems arise and that there are techniques that can be used to address them — and undoubtedly will be used as MODx Revolution matures. But I also know that there are limits to improving the performance of computer software without using different algorithms and architecture. So if someone questions the architecture or what algorithms are being used, they are not being inappropriate just because they haven’t read the code.
          __________________
          JRG
          • 28215
          • 4,149 Posts
          Good discussion. jrg, I definitely don’t think it inappropriate in any circumstance to ask questions.

          By the way, for reference, if you look at the cached version of an Element (such as a plugin), you find something like this:

          function elements_modplugin_3($scriptProperties= array()) {
             global $modx;
             if (is_array($scriptProperties)) {
                extract($scriptProperties, EXTR_SKIP);
             }
             /* plugin code here... */
          }
          


          Meaning that all modScript objects (which extends modElement; plugins or snippets extend modScript) run in an isolated function that has a few things of note:


          • The $modx object, as a global.
          • The $scriptProperties array, which is an array of properties passed into the Element.
          • All the keys of the $scriptProperties array are extracted into PHP vars (such as $tpl, $user, etc). This was mainly for backwards compatibility with Evo code; however, it will likely remain.

          All of the variables instantiated in the Element, with the exception of the MODx object (and whatever is returned) are destroyed after the Element is run, since they are encapsulated in the function.

          Hope that sheds some light on the subject.

          P.S. This should work with OnUserActivate:

          $user =& $scriptProperties['user'];
          $username = $user->get('username');
          


          $modx->user is not appropriate there, as $modx->user *always* refers to the client’s user - the user in the browser’s current session. IOW, you. That may not be what you want in the OnUserActivate event.
            shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
            • 3749
            • 24,544 Posts
            Shaun, thanks for correcting me about the scriptProperties array in plugins. Am a correct in assuming that in the case of a plugin, they would normally contain only the plugin’s own properties? In that case they wouldn’t be of much use in jrg’s situation.

            jrg: I didn’t mean to sound so defensive (or offensive), I was coming off a bad day of unsuccessful debugging (actually, a whole unsuccessful day trying to get the debugger working again). We certainly welcome constructive criticism of the MODx architecture as well as questions about how to do things. smiley

              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
              • 28215
              • 4,149 Posts
              Quote from: BobRay at Jan 05, 2011, 01:04 AM

              Shaun, thanks for correcting me about the scriptProperties array in plugins. Am a correct in assuming that in the case of a plugin, they would normally contain only the plugin’s own properties? In that case they wouldn’t be of much use in jrg’s situation.

              They contain the Plugin’s default properties, as well as any Property Sets’ properties that might be attached to the Plugin on that Event.
                shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
                • 14877
                • 110 Posts
                Perfect. That’s great. I am happy on two points: the architecture (I like the isolation mechanism) and an explanation of the plugin’s environment. smiley

                So that means the ’user’ parameter is being passed, but has also had a variable by the same name set up (so extracting them oneself is simply redundant).

                Quote from: splittingred at Jan 04, 2011, 11:13 PM

                Good discussion. jrg, I definitely don’t think it inappropriate in any circumstance to ask questions.

                By the way, for reference, if you look at the cached version of an Element (such as a plugin), you find something like this:

                function elements_modplugin_3($scriptProperties= array()) {
                   global $modx;
                   if (is_array($scriptProperties)) {
                      extract($scriptProperties, EXTR_SKIP);
                   }
                   /* plugin code here... */
                }
                


                Meaning that all modScript objects (which extends modElement; plugins or snippets extend modScript) run in an isolated function that has a few things of note:


                • The $modx object, as a global.
                • The $scriptProperties array, which is an array of properties passed into the Element.
                • All the keys of the $scriptProperties array are extracted into PHP vars (such as $tpl, $user, etc). This was mainly for backwards compatibility with Evo code; however, it will likely remain.

                All of the variables instantiated in the Element, with the exception of the MODx object (and whatever is returned) are destroyed after the Element is run, since they are encapsulated in the function.

                Hope that sheds some light on the subject.

                P.S. This should work with OnUserActivate:

                $user =& $scriptProperties['user'];
                $username = $user->get('username');
                


                $modx->user is not appropriate there, as $modx->user *always* refers to the client’s user - the user in the browser’s current session. IOW, you. That may not be what you want in the OnUserActivate event.
                  __________________
                  JRG
                  • 14877
                  • 110 Posts
                  Quote from: BobRay at Jan 05, 2011, 01:04 AM

                  [...]

                  jrg: I didn’t mean to sound so defensive (or offensive), I was coming off a bad day of unsuccessful debugging (actually, a whole unsuccessful day trying to get the debugger working again). We certainly welcome constructive criticism of the MODx architecture as well as questions about how to do things. smiley



                  No problem. I hope things are going better for you (and continue that way throughout 2011).
                    __________________
                    JRG