public static function getGroupsByUser($userId, $recursive = true)
	{
		// Creates a simple unique string for each parameter combination:
		$storeId = $userId . ':' . (int) $recursive;

		if (!isset(self::$groupsByUser[$storeId]))
		{
			// Guest user (if only the actually assigned group is requested)
			if (empty($userId) && !$recursive)
			{
				$result = array(\Component::params('com_members')->get('guest_usergroup', 1));
			}
			// Registered user and guest if all groups are requested
			else
			{
				$db = App::get('db');

				// Build the database query to get the rules for the asset.
				$query = $db->getQuery();
				$query->select($recursive ? 'b.id' : 'a.id');
				if (empty($userId))
				{
					$query->from('#__usergroups', 'a')
						->whereEquals('a.id', (int) \Component::params('com_members')->get('guest_usergroup', 1));
				}
				else
				{
					$query->from('#__user_usergroup_map', 'map')
						->whereEquals('map.user_id', (int) $userId)
						->join('#__usergroups AS a', 'a.id', 'map.group_id', 'left');
				}

				// If we want the rules cascading up to the global asset node we need a self-join.
				if ($recursive)
				{
					$query->joinRaw('#__usergroups AS b', 'b.lft <= a.lft AND b.rgt >= a.rgt', 'left');
				}

				// Execute the query and load the rules from the result.
				$db->setQuery($query->toString());
				$result = $db->loadColumn();

				// Clean up any NULL or duplicate values, just in case
				Arr::toInteger($result);

				if (empty($result))
				{
					$result = array('1');
				}
				else
				{
					$result = array_unique($result);
				}
			}

			self::$groupsByUser[$storeId] = $result;
		}

		return self::$groupsByUser[$storeId];
	}