How to add a User to a Group (via API)?

Permalink 2 users found helpful
I'm integrating with MailChimp and am stuck on something that's simple, I'm sure. My MailChimp webhook registers a new user when they subscribe to my email list. I need to then add them to a specific group but I'm not getting what I expected.

I say:
$user = new User($uName, $uPassword);
$group1 = Group::getByName('Group1');
$user->enterGroup($group1);

It says:
mysql error: [1048: Column 'uID' cannot be null] in EXECUTE("INSERT INTO UserGroups (uID,gID,type,ugEntered) VALUES (NULL,'4','','2009-12-05 15:16:24')")

So apparently when I say $user->enterGroup() it doesn't have an ID associated with $user, even though I just created $user. It seems logical to me, but it's not working. Does anyone know what's up?

Benji
View Replies:
ijessup replied on at Permalink Reply
ijessup
I'm sure you've figured this out, but you need to add the user to the DB.
$user = new User($uName, $uPassword)
Doesn't do that for you.

I'm not exactly sure how you commit a new user to the DB, but look at the registration page's controller and see how it does it.
Benji replied on at Permalink Reply
Benji
Thanks. Yeah, I already registered the user using UserInfo::add. And I figured out there's nothing wrong with the enterGroup code I posted. I had other problems that were preventing it from working right.
ijessup replied on at Permalink Reply
ijessup
Ahh cool.

I've never tried working with groups via API, but I figured I'd at least point you in a general direction. :)
kino replied on at Permalink Reply
kino
check userinfo.php
public function updateGroups($groupArray) {
kino replied on at Permalink Reply
kino
<?php  
$u = new User();
$u->getByUserID( $uID);
$group1 = Group::getByName('Group1');
$u->enterGroup($group1);
?>
kino replied on at Permalink Reply
kino
Hmm.
It is not work.
kino replied on at Permalink Reply
kino
success.

$g = Group::getByName($group);      $uo->updateGroups(array($g->getGroupID()));


This code is then used as follows.
if(!$error){
         $data = array('uName' => $username, 'uPassword' => $password, 'uEmail' => $email);
         $uo = UserInfo::add($data);
         if (is_object($uo)) {
            if($group!=''){
               $g = Group::getByName($group);
               $uo->updateGroups(array($g->getGroupID()));
            }
            $result = t('success import %s (%s)', $username,$email);
         }
      } else {
            $result = t('           import error %s (%s)', $username,$email);
            $this->error[] .= implode($error,'<br />') ;
      }
Benji replied on at Permalink Reply
Benji
Thanks for helping out, but as I said above, the code I originally posted works. I had some other problems that were giving me errors, but I resolved them, so using User::enterGroup is correct.

UserInfo::updateGroups is a dangerous method to use if you're just trying to assign a user to a group in a one-off kind of way. The updateGroups method expects you to pass an array of ALL the groups you want the user to be in. Any group that isn't in the array is removed from the UserGroups table in the database -- so the user won't be in them anymore. It's a good method to use in the Edit User part of the dashboard, for instance, where you have a bunch of checkboxes for any groups you want the user to be in, but it's a dangerous method to use in other circumstances where you're just trying to take a group of immediate concern and add the user to it without disturbing any of their other group memberships.

So, for just a "add to group", the User::enterGroup method is the best way.
kino replied on at Permalink Reply
kino
If you do this?

$uo = UserInfo::getByUserName($username);
         if (is_object($uo)) {
            if($group!=''){
               $groups = Group::getByName($group);
               $gIDs[]= $groups->gID;
               $groups = new GroupList($uo,true);
               foreach ($groups->gArray as $g){
                  if(array_search($g->gID,$gIDs)===false){
                     $gIDs[] = $g->gID;
                  }
               }
               $uo->updateGroups($gIDs);
            }
            $result = t('success import %s (%s)', $username,$email);
         }
dg1 replied on at Permalink Reply
I'm curious how to get this working. I am trying to add a user to a group "unvalidated" after the user registers so the admin knows who needs approval and activation. I set up a method to get invoked on the event on_user_add and I know the code is getting executed because I added some logging calls. I also added logging to verify that I am getting the correct user and group and all seems fine except the user never gets added to the group! Here is my code:

public function setupUserJoinInfo($ui)
{  
   Loader::model('groups');
   // get group
   $g = Group::getByName('unvalidated');
   ApplicationUser::logToFile("test.log", $g->getGroupName());
   // add user to this group
   if ($g <> 0) {           ApplicationUser::logToFile("test.log", $ui->getUserName());
       $ui->enterGroup($g);
    }  
}


Any ideas on what I am doing wrong? Thanks for any help you can give.
Tony replied on at Permalink Reply
Tony
maybe instead of

if ($g <> 0) {

try

if ( is_object($g) ) {
dg1 replied on at Permalink Reply
I changed the code to say is_object and it still does not work. I know it was getting past that point anyway because my log message was getting written and it was logging the correct user name and group. I just wish the enterGroup would work.

On a positive note, I just discovered how mail templates work and I created my own template and wrote code to email the administrator when a new user gets created and needs activation as an alternative to the group method I was trying above. And it works!

C5 is the most amazing CMS! I cannot believe how flexible and clean it is. The C5 designers are very very smart people!!
Benji replied on at Permalink Reply
Benji
Hi. I'm guessing that the problem here is that you're trying to invoke the enterGroup method on a UserInfo object (guessing because the code you've posted has $ui->enterGroup). But enterGroup is only a method of the User object, not UserInfo. So if I'm right, the easiest way to proceed would probably be to do $u = $ui->getUserObject() and then do $u->enterGroup($g). Hope that helps!
synlag replied on at Permalink Reply
synlag
thx for this one, i definitely need this to put a user into group on form submission, beacause i need two stages of a registering process (the easy register for registered users and the advanced vor trusted users)
dg1 replied on at Permalink Reply
Thank you so much! With your changes, my code is working now. I obviously still have a lot to learn but I'm just glad it's working now. Thanks again for your help!
cyandesigns replied on at Permalink Reply
Hi

This seems like the closest thing that I've found on the forums for what I'm looking for.

I want my new registrants to be able to choose from 6 of my groups to be placed in when they register.

I've created a custom attribute with the groups i want them to choose from, but I've been baffled trying to find the proper code sequence to get this to function (ie: the link between the groupID and the attributeID).

I've added a new user notification (might have been on one of your forum posts) so I basically want to add the hook on add_user.

Thoughts?
Benji replied on at Permalink Reply
Benji
It sounds like you're actually making this harder for yourself than it needs to be. There's no need for a custom attribute (unless I'm missing something…), just add them to the group(s) they specify. For instance, your page might have:
<h4>What&rsquo;s your primary interest here?</h4>
<ul>
<li><input type="radio" id="training" name="interest_group" value="training" /><label for="training">Dog Training</label></li>
<li><input type="radio" id="breeding" name="interest_group" value="breeding" /><label for="breeding">Dog Breeding</label></li>
<li><input type="radio" id="bling" name="interest_group" value="bling" /><label for="bling">Pimp My Pooch</label></li>
</ul>

…and then your controller would have something like:
<?php
$gTraining = Group::getByName('Training');
$gBreeding = Group::getByName('Breeding');
$gBling = Group::getByName('Bling');
$interest = $_POST['interest_group'];
switch ($interest) {
case 'training': $u->enterGroup($gTraining);
case 'breeding': $u->enterGroup($gBreeding);
case 'bling': $u->enterGroup($gBling);
}
?>

Of course, there would be more to your controller, but those are the pertinent parts. Then you would see the groups that they're in right on their user page, so I don't think there would be any need for a separate attribute unless you're trying to do something fancy that you didn't explain.

Hope that helps!
cyandesigns replied on at Permalink Reply
Hi Benji

For some reason I'm not receiving any notifications from threads I'm following so I just read your response now...Sorry about that.

It looks like from what your saying that I could add a simple form for them to be added to a group. Would I be able to add this to the registration page?

Essentially I want them to be able to choose which group they are going to be associated with when they register. They wouldn't have the option of multiple groups, just one. This seems like it's right on the cusp of being the way to go.

I added a custom attribute to that it would appear on the registration page and I thought there might be a way to correlate the two...

Hope this makes things a little clearer.
Benji replied on at Permalink Reply
Benji
Hi cyandesigns,

OK, I see what you're trying to do now. In that case, you could just hook into the on_user_add event and make a little code that adds the user to the group based on the attribute. You might've already visited the Events documentation page, which ishttp://www.concrete5.org/help/building_with_concrete5/developers/mv... There's kind of a little example there of using the on_user_add event.

So, in your method, you would do something like:
<?php
public function addToGroupByAttritube($ui) {
$group_name = $ui->getAttribute('interest_group'); //you could also use the magic method $ui->getUserInterestGroup() for the same result
$g = Group::getByName($group_name);
$u = $ui->getUserObject();
$u->enterGroup($g);
}
?>

The thing you'd have to make sure of is that you set up your Groups with the exact same names as your Interest Groups attribute values so that the above code can find each group based on the attribute.

If this or the on_user_add Event thing doesn't make sense to you, just ask me again and I'll go over it in more detail.
cyandesigns replied on at Permalink Reply
Hi Benji

Thanks again for your time.

I have already set up an on_user_add event to send me an email when a new user registers. So based on what you sent I added the following to the bottom of my site_events.php -->

<?php
   Events::extend('on_user_add',             /* event */
                  'ApplicationUser',         /* class */ 
                  'setupUserJoinInfo',       /* method */
                  'models/application_user.php'); 
   Events::extend('on_user_add',
               'RegisterGroup',
               'addToGroupByAttribute',
               'models/register_group.php');


and I added a new model called "register_group.php" with the following code (per your specs) -->

<?php
class RegisterGroup extends Object {
   public function addToGroupByAttribute($ui) {
   $group_name = $ui->getAttribute('department'); //you could also use the magic method $ui->getUserInterestGroup() for the same result
   $g = Group::getByName($group_name);
   $u = $ui->getUserObject();
   $u->enterGroup($g);
   }


Then - I changed the Group names and the attribute ('department') selection values to be identical.

I think I did everything correctly but no joy.

I appreciate all of your help!
Benji replied on at Permalink Reply
Benji
Hey cyandesigns,

First of all, the first Events::extend call you have looks like it's copied exactly from the documentation…and I just want to make sure that you're actually doing something with that, because otherwise it would be unnecessary. I just want to make sure you know that.

The code would work fine, but the problem I didn't realize is this: When you add a user, c5 first adds their username, email address, and password to the database, and then circles back and adds their attributes. The on_user_add event therefore fires the instant the user is added and before they have any attributes. So when it executes the addToGroupByAttribute method and looks for the user's "department" attribute, they don't have one yet, so nothing happens.

Sorry I didn't realize that before…I guess I never tried to work with attributes in the on_user_add event, so I was a little puzzled myself at first. But when I tested it, it became obvious that the user didn't yet have any attributes. You might want to start a new thread to ask around and see if someone has dealt with that before and discovered a possible workaround. I tried triggering an update event amidst the add event hoping that might catch the attributes, but no such luck. Nothing else comes to mind at the moment, but I'll let you know if I think of something. Probably the Core Team at least would have an idea if you can get their attention.
cyandesigns replied on at Permalink Reply
Hey Benji

I appreciate all of your help up to this point regardless of whether it worked or not.

These kinds of things really help me to learn a lot more about the core and how it functions as well as a little bit more about php with each modification - so no worries.

I'll have to think about this a little bit more and tinker around with the core for some inspiration.

Thank you
Benji replied on at Permalink Reply
Benji
Hey, no problem. The other possibility you might consider if you're not afraid of straying from the prefab c5 a little, is to make your own registration page and controller, drawing on c5's core registration functionality from your own class. I've done this so that I could integrate with MailChimp (before the MailChimp plugin was available in the marketplace) and the advantage is that you can do whatever you want in the registration process. That's part of why I never thought of the difficulty of adding users to groups on signup--because it isn't an issue if you roll your own.

The drawback is that you might have to maintain your registration page for future updates. But probably not as long as you code it intelligently and it does what you want.

Another advantage is that you can improve the spam-filtering without resorting to a CAPTCHA, which I like to avoid if at all possible.

I could probably procure some example files if you're interested at all.
cyandesigns replied on at Permalink Reply
I'm definitely not afraid of it, but I need to make sure I fully understand what's doing before I muck things up. I'm learning php as I go...

Would the custom registration page be outside the core as an override or would I be manipulating the core?

Examples are ALWAYS welcome if you don't mind. It makes it a lot easier for me to understand if I can see what the code looks like and know what the desired effect is.

Again - MUCH APPRECIATED!
Benji replied on at Permalink Reply
Benji
Hi cyandesigns,

I started a new thread with some example files for you over herehttp://www.concrete5.org/index.php?cID=72697... since it didn't really fit in this topic anymore. To answer your question, you wouldn't be tampering with the core. You should read about single pages and stuff in the documentation.

As an aside, I later realized the obvious, but it still wasn't of any help. That is, when the event runs, the user attributes that got submitted with the registration/add form are still available as POST variables, so you could just use those to determine which group the user should get added to. Makes sense, since you can't query the attributes directly as we already discovered because they don't yet exist, right? But……

When I tried it out, I couldn't for the life of me get the $u->enterGroup($g) to work…for no apparent reason. I logged everything that happened: I had the correct Group object and the correct User object, but it strangely would not work. It worked fine in a block or anywhere else, but not in the event.

Anyway, you could try it if you want -- maybe it's just me. Or maybe someone else knows why it doesn't work in the event. It really shouldn't be this hard to add a user to a group on registration…I think c5 oughtta work on that.

So let me know how it goes with a custom registration controller, if you decide to do that.
Benji replied on at Permalink Reply
Benji
Hi again,

Nevermind what I said before about the UserInfo::enterGroup method not working in the on_user_add event. Here's what you need to do: in your method that gets called on the event, use this code:
$group_number = $_POST['akID'][18]['atSelectOptionID'][0]; // replace this key with your actual POST variable key
switch ($group_number) {
   case 4: $group_name = 'Iron';      break;
   case 5: $group_name = 'Oxygen';      break;
   case 6: $group_name = 'Ytterbium';   break;
}
$g = Group::getByName($group_name);
$u = $ui->getUserObject();
$u->enterGroup($g);

Assuming you're using the c5 registration page, you'll need to look up the actual $_POST variable it's using for your "department" attribute and replace my $_POST['akID'][18]['atSelectOptionID'][0] with that key. If you're using your own registration page, then just use whatever $_POST variable corresponds to your input, like $_POST['department'].

The only time this code won't work is if you add a user via the Dashboard. But, you don't need it to work then because you can check the groups that you want the user added to when you add them.

Sorry if I led you astray with the whole custom controller deal. Any other questions, just ask.
cyandesigns replied on at Permalink Reply
YOU ROCK!

It took me just a little bit to understand what ID numbers had to be found but you've done it.

I can't tell you enough how awesome this is. You should TOTALLY write up a "How to" on this. I think it would benefit a lot of people.

Thanks for everything!
Benji replied on at Permalink Reply
Benji
Hehe, you're welcome. Glad I could help.
rc255 replied on at Permalink Reply
rc255
Hi there Benji, I know this link is really old, nut I'm looking to do exactly this process. I have worked out the 'akID' but I'm not entirely sure where this block of code should sit...

I've created a custom registration page in /root/single_pages/register.php - does this code go into this page?

When I put the code at the bottom of the page, I get the following error:

Fatal error: Call to a member function getUserObject() on a non-object in /var/www/cobolt/single_pages/register.php on line 165

which is referring to the line: $u = $ui->getUserObject();

If you can point me in the right direction, you'll make my day!

Cheers