We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 25663 MODX Staff
    • 12,272 Posts
    It started life with the purpose of checking the logged in user’s groups, and returning a chunk if they were a member of the passed in groups. It wound up being rewritten by Jason as a demonstration of how to do some pretty cool stuff as a real class... I’ll let him handle the details on that. This is VERY handy for custom web applications and makes it easier to implement conditional "blocks" like in some other CMSes. I suppose it could be adapted to check sessions, cookies or some other prameter too, but I created it to render admin menus for custom web apps. I think it merits distribution in 0.9.1 as a new default snippet.

    #::::::::::::::::::::::::::::::::::::::::
    # Snippet name: MemberCheck 
    # Short Desc: checks logged in groups and displays a chunk
    # Version: 1.0
    # Created By Ryan Thrash (vertexworks.com)
    # Sanitized By Jason Coward (opengeek.com)
    #
    # Date: November 29, 2005
    #
    # Changelog: 
    # Nov 29, 05 -- initial release
    #
    #::::::::::::::::::::::::::::::::::::::::
    # Description: 	
    #	Checks to see if users belong to a certain group and 
    #	displays the specified chunk if they do. Performs several
    #	sanity checks and allows to be used multiple times on a page.
    #
    # Params:
    #	&groups [array] (REQUIRED)
    #		array of webuser group-names to check against
    #
    #	&chunk [string] (REQUIRED)
    #		name of the chunk to use if passes the check
    #
    #	&ph [string] (optional)
    #		name of the placeholder to set instead of directly retuning chunk
    #
    #	&debug [boolean] (optional | false) 
    #		turn on debug mode for extra troubleshooting
    #
    # Example Usage:
    #
    #	[[MemberCheck? &groups=`siteadmin, registered users` &chunk=`privateSiteNav` &ph=`MemberMenu` &debug=`true`]]
    #
    #	This would place the 'members-only' navigation store in the chunk 'privateSiteNav'
    #	into a placeholder (called 'MemberMenu'). It will only do this as long as the user 
    #	is logged in as a webuser and is a member of the 'siteadmin' or the 'registered users'
    #	groups. The optional debug parameter can be used to display informative error messages 
    #	when configuring this snippet for your site. For example, if the developer had 
    #	mistakenly typed 'siteowners' for the first group, and none existed with debug mode on, 
    #	it would have returned the error message: The group siteowners could not be found....
    #
    #::::::::::::::::::::::::::::::::::::::::
    
    # debug parameter
    $debug = isset($debug)? $debug: false;
    
    # check if inside manager
    if ($m = $modx->insideManager()) {
    	return ''; # don't go any further when inside manager
    }
    
    if(!isset($groups)) {
    	return $debug? '<p>Error: No Group Specified</p>': '';
    } 
    
    if(!isset($chunk)) { return $debug? '<p>Error: No Chunk Specified</p>': ''; }
    
    # turn comma-delimited list of groups into an array
    $groups = explode(',', $groups);
    
    if (!class_exists('MemberCheck')) {
    	class MemberCheck {
    		static $instance = NULL;
    		var $allGroups = NULL;
    		var $debug;
    		
    		function getInstance($debug=false) {
    			global $modx;
    			if (self::$instance == NULL) {
    				self::$instance= new MemberCheck($debug);
    			}
    			return self::$instance;
    		}
    	
    		function MemberCheck($debug=false) {
    			global $modx;
    			$this->debug= $debug;
    			if ($debug) {
    				$this->allGroups= array(); 
    				$tableName= $modx->getFullTableName('webgroup_names');
    				$sql= "SELECT name FROM $tableName";
    				if ($rs= $modx->db->query($sql)) {
    					while ($row= $modx->db->getRow($rs)) {
    						array_push($this->allGroups, stripslashes($row['name']));
    					}
    				}
    			}
    		}
    		
    		function isValidGroup($groupName) {
    			$isValid = !(array_search($groupName, $this->allGroups)===false);
    			return $isValid;
    		}
    		
    		function getMemberChunk(&$groups,$chunk) {
    			global $modx;
    			$o= '';
    			if (is_array($groups)) {
    				for ($i=0; $i<count($groups); $i++) {
    					$groups[$i]= trim($groups[$i]);
    					if ($this->debug) {
    						if (!$this->isValidGroup($groups[$i])) return "<p>The group <strong>" . $groups[$i] . "</strong> could not be found...</p>";
    					}
    				}
    				
    				$check = $modx->isMemberOfWebGroup($groups);
    				
    				$chunkcheck = $modx->getChunk($chunk);
    				
    				$o.= ($check && $chunkcheck)? $chunkcheck : '';
    				if (!$chunkcheck) $o.= $this->debug? "<p>The chunk <strong>$chunk</strong> not found...</p>": '';
    			} else {
    				$o.= "<p>No valid group names were specified!</p>";
    			}
    			return $o;
    		}
    	}
    }
    
    $memberCheck= MemberCheck::getInstance($debug);
    return $memberCheck->getMemberChunk($groups, $chunk);
    


    Let’s test it and see what happens... feedback appreciated.
      Ryan Thrash, MODX Co-Founder
      Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
      • 22303 MODX Staff
      • 10,725 Posts
      Purpose of my rewrite of Ryan’s snippet this way: I wanted to provide an example of a singleton pattern implemented in a snippet, to show how it can be used to increase performance, and decrease memory resources when reusing a snippet multiple times per page.

      A singleton is a design pattern that is meant to restrict the instantiation of a class to one single (or in some cases, a few) object. In traditional OO languages like Java, it would also mean making the constructor of the class private or protected to keep it from being instantiated the traditional way [e.g. $object= new Class()], but in the PHP paradigm, where static classes do not exist across requests to the webserver (unlike Java), the only purpose here is to limit the SQL calls and memory resources used to the first instance of the snippet on a page. Each subsequent use of the snippet will simply reuse the object instance created by the evaluation of the first snippet.

      I’d love to hear your feedback, comments, or alternate approaches.
        • 6726
        • 7,075 Posts
        Not from the technical point of view, it would be very nice having this in 0.9.1, a great new feature grin

        Kind of UI Levels implementation, if I understand what it does correctly...

        Thanks for this !
        I’ll test it and report...

        Edit : Idea -> could this be used as a shortcut to multi-lingual websites ? If we had a language field to the users table it could work, wouldn’t it ? The only downside is you would have to be logged in to have the proper language displayed... I don’t know just throwing ideas there...

          .: COO - Commerce Guys - Community Driven Innovation :.


          MODx est l&#39;outil id
          • 25663 MODX Staff
          • 12,272 Posts
          I’m sure it could be used for that David. Planning on adding it for 0.9.1, but wanted some testing first, just in case wink
            Ryan Thrash, MODX Co-Founder
            Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
            • 22303 MODX Staff
            • 10,725 Posts
            All this snippet really does is confirm membership in one or more groups and then output an optional chunk specified in the snippet configuration if they are members.

            I actually worked with a framework in my J2EE days that handled languages (as well as other customization and personalization features) by having a prioritized way of serving content by context. In other words, if they were logged in, they would get the language they chose to view the site it, but without authentication, it would fall back to client locale settings. And now I have an idea to use this concept for localization efforts in conjunction with two other big items, database abstraction and content versioning. The idea would be that any object in the repository could have multiple versions that could be used in various ways, from tracking history to providing multiple versions of the resource for various contexts (i.e. like locale and/or language). The database abstraction work would add the versioning capability and a plugin could be used to determine the context and select the proper version.

            Just some ideas...
              • 28042 ☆ A M B ☆
              • 24,524 Posts
              I use cookies for storing the user’s language preference, because sessions can time out and the user would get dumped back into the default until he logged in again. But storing a user’s language preference in the webuser_attributes table would be trivial.
                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
                • 22303 MODX Staff
                • 10,725 Posts
                And you can still use the cookie as part of this system for cross-session contextual preferences for anonymous users, or to automatically login users who choose to set a cookie.
                  • 25663 MODX Staff
                  • 12,272 Posts
                  Quote from: OpenGeek at Dec 01, 2005, 11:27 AM
                  And now I have an idea to use this concept for localization efforts in conjunction with two other big items, database abstraction and content versioning.  The idea would be that any object in the repository could have multiple versions that could be used in various ways, from tracking history to providing multiple versions of the resource for various contexts (i.e. like locale and/or language).  The database abstraction work would add the versioning capability and a plugin could be used to determine the context and select the proper version.
                  Now that’s a cool idea that spaws a slight twist of an idea. We could actually use "tagging" to assign different page versions to different languages. So when you create a new page, it could be automatically tagged as the "default" language. If a user came in and translated that page, they could then hit a button to spawn a new version tagged with that language. Nice and pretty simple from a usability standpoint!
                    Ryan Thrash, MODX Co-Founder
                    Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me