Registrant Group Addon - Add users to a group if they add a certain code?

Permalink
Hi,

I'm trying to tweak the controller in the Registrant Group addon so it only adds users to a group if they've entered a certain code (12345):

public function on_user_add($userInfo) {
// Get attribute
$ak = CollectionAttributeKey::getByHandle('membership_code');
if ( $ak == "12345") {
$co = new Config();
$gID = $co->get('REGISTRANT_GROUP_ID');
if (!empty($gID)) {
Loader::model('groups');
$group = Group::getByID($gID);
if (!empty($group)) { //check that group wasn't deleted
$userInfo->getUserObject()->enterGroup($group);
}
}
}


This doesn't seem to work, any ideas?

Thanks

Dave

madesimplemedia
 
hutman replied on at Permalink Reply
hutman
I believe with this code you are getting the attribute key, not the attribute value, so you would need to change

$ak = CollectionAttributeKey::getByHandle('membership_code');

to be

$ak = $userInfo->getAttribute('membership_code');

This will give you this user's attribute value, then you can compare it to your specific code and move forward with the rest. I haven't used this add-on before, but I believe this should work.
mnakalay replied on at Permalink Reply
mnakalay
Hello,
There are several problems in your code.

First I am going to assume that you actually did save the code value to an attribute against that user. If you didn't, your code won't do anything.

Second, you are getting the attribute but not it's value for that particular user so it will never be equal to your code

You need to do
$code = $userInfo->getAttribute('membership_code');
if ($code === '12345') {
madesimplemedia replied on at Permalink Reply
madesimplemedia
Thank you both.

I believe I have saved the code correctly because when I view the user in the dashboard, there is the correct value for the attribute.

I've updated the registrant group add-ons controller with your code, but they are still not being added to the group.

What else can I check?
hutman replied on at Permalink Reply
hutman
Start adding echo and/or die statements throughout the code and see what is happening and if it what you expect.
mnakalay replied on at Permalink Reply
mnakalay
I remember now, I know what the problem is. The on_user_add event is actually fired BEFORE the attributes are saved. There was even an article written about it and I implemented that solution at the time and it worked pretty well.

Basically you need an override to the core to create a new event on_attribute_saved.

The article is here:http://www.werstnet.com/blog/a-more-useful-on-user-add-event-for-co...

If you don't feel like going that way, there is a possible hack. When the user is added, keep the code as it is but put them in a temporary group. Then use the event on_user_enter_group to check the code and put them in the proper group. A 2 step process if you want. I haven't tried it but it should work
madesimplemedia replied on at Permalink Reply
madesimplemedia
Thanks for the info. I went for the first option you propose.

I've followed the steps and I'm trying to add the user to the group "Franchise" if they add the attribute with the handle "membership_code" or 12345.
I'm not getting an error, but the user isn't being added to the group either. Wish I knew more PHP but it's my weakness for sure.
Here is my user_events.php code:

<?php 
defined('C5_EXECUTE') or die(_("Access Denied."));
class UserInfoEvents extends Object {
   public function attributesSaved($ui){
      // run your custom code here
      // the $ui object is the $process variable from the register.php controller
      // you can do anything here, send a second email to the site admin, 
      // create a custom page for the new user, whatever
      $u = new User(); //get the current user
      $ak = $ui->getAttribute('membership_code');
      $ak = str_replace(' ', '', $ak);
      if ( $ak === "12345") {
         if(!is_object(Group::getByName('Franchise'))) {
            if(!$u->inGroup(Group::getByName('Franchise'))){
               $u->enterGroup('Franchise');
mnakalay replied on at Permalink Reply
mnakalay
You have a problem in your code
This line
if(!is_object(Group::getByName('Franchise'))) {

Should be
if(is_object(Group::getByName('Franchise'))) {

where you delete the exclamation mark

Also I am not 100% sure the new user gets logged in every time. There might be some edge case where he doesn't so you might want to replace
$u = new User();

try
$u = $ui->getUserObject();
madesimplemedia replied on at Permalink Reply
madesimplemedia
Hi,
Thanks for your reply, still struggling to get this working, my user_events code is now:

<?php 
defined('C5_EXECUTE') or die(_("Access Denied."));
class UserInfoEvents extends Object {
   public function attributesSaved($ui){
      // run your custom code here
      // the $ui object is the $process variable from the register.php controller
      // you can do anything here, send a second email to the site admin, 
      // create a custom page for the new user, whatever
      //$u = new User(); //get the current user
      $u = $ui->getUserObject();
      $ak = $ui->getAttribute('membership_code');
      $ak = str_replace(' ', '', $ak);
      if ( $ak === "123456") {
         if(is_object(Group::getByName('Franchise'))) {
            if(!$u->inGroup(Group::getByName('Franchise'))){


I tried both with $u = new User(); and with $u = $ui->getUserObject();

Thanks
mnakalay replied on at Permalink Reply
mnakalay
Could you just post the whole code here, it would be easier
madesimplemedia replied on at Permalink Reply
madesimplemedia
Just thinking, when users register, I've enabled email validation so they need to click the link, then login.
Will this work with this code?
mnakalay replied on at Permalink Reply
mnakalay
You could use different events then. Try on_user_validate or on_user_activate
madesimplemedia replied on at Permalink Reply
madesimplemedia
I've got it set to on_user_validate in site_events.php file:
<?php 
// syntax is like this:
// Events::extend($event, $class, $method, $filename, $params = array());
// so we need ours to look like this:
Events::extend('on_user_validate', 'UserInfoEvents', 'attributesSaved', 'models/user_events.php');
?>


However, I'm using the Event Tester addon and it doesn't seem to befiring, there is nothing in the logs when I validate the users email.

My user_events.php is:
<?php 
defined('C5_EXECUTE') or die(_("Access Denied."));
class UserInfoEvents extends Object {
   public function attributesSaved($ui){
      // run your custom code here
      // the $ui object is the $process variable from the register.php controller
      // you can do anything here, send a second email to the site admin, 
      // create a custom page for the new user, whatever
      //$u = new User(); //get the current user
      $u = $ui->getUserObject();
      $ak = $ui->getAttribute('membership_code');
      $ak = str_replace(' ', '', $ak);
      if ( $ak === "12345") {
         if(is_object(Group::getByName('Franchise'))) {
            if(!$u->inGroup(Group::getByName('Franchise'))){


I've enabled events in the config too, site.php, although just read this is only needed for older versions of C5 anyway:
...
define('ENABLE_APPLICATION_EVENTS', true);


And my register.php controller:
<?php 
defined('C5_EXECUTE') or die("Access Denied.");
class RegisterController extends Concrete5_Controller_Register {
   public function do_register() {
      $registerData['success']=0;
      $userHelper = Loader::helper('concrete/user');
      $e = Loader::helper('validation/error');
      $ip = Loader::helper('validation/ip');      
      $txt = Loader::helper('text');
      $vals = Loader::helper('validation/strings');
      $valc = Loader::helper('concrete/validation');
      $username = $_POST['uName'];
      $password = $_POST['uPassword'];
      $passwordConfirm = $_POST['uPasswordConfirm'];
      // clean the username


When I log in as admin and check the newly registered user, I can see my custom attribute (Franchise) is correct saved under the users' attributes but they aren't being added to the correct group.

Any idea why it doesn't appear to be firing that event?

Thanks
mnakalay replied on at Permalink Reply
mnakalay
You have a problem in your join controller code. you are trying to fire that event yourself:
Events::fire('on_user_validate', $process);

Don't do that.

First, at this point, the user is not validated yet. The user is only validated when he clicks on the link in the email sent to him. If registration doesn't require validation, that event is never fired.

Second, the event is fired by Concrete5 itself so you shouldn't do it in your code.

Here's what happens when you ask for email validation and the user receives an email asking to click a link to validate their email:
The link opens the login page and calls the function v() that you can find in the login single page's controller
// responsible for validating a user's email address
   public function v($hash = '') {
      $ui = UserInfo::getByValidationHash($hash);
      if (is_object($ui)) {
         $ui->markValidated();
         $this->set('uEmail', $ui->getUserEmail());
         $this->set('validated', true);
      }
   }

That function checks that the link is genuine and then validate the user by calling the function markValidated() which is in concrete\core\models\userinfo.php
function markValidated() {
         $db = Loader::db();
         $v = array($this->uID);
         $db->query("update Users set uIsValidated = 1, uIsFullRecord = 1 where uID = ?", $v);
         $db->query("update UserValidationHashes set uDateRedeemed = " . time() . " where uID = ?", $v);
         Events::fire('on_user_validate', $this);
         return true;
      }

And you can see that the proper event is fired in that function.

So my advice is delete that line from your own code and try again.
madesimplemedia replied on at Permalink Reply
madesimplemedia
Thanks, I have removed that line from the controller.

So the site_events.php file I have created is an override for the on_user_validate in concrete\core\models\userinfo.php?
madesimplemedia replied on at Permalink Reply
madesimplemedia
Still isn't working after removing that line from the controller :(
mnakalay replied on at Permalink Reply
mnakalay
no the site_events is not an override, it listens to and reacts to events.

I just thought of something. Are you actually modifying the original add-on? IF yes, than the event listening is defined in the package's controller in the on_start function.

Check that and if I'm correct, you can get rid of the site_events stuff and make sure you have the proper on_start event listening in place.

If that still doesn't work, I am afraid there isn't much more I can do unless you're willing to send me the code so I can test it myself.
madesimplemedia replied on at Permalink Reply
madesimplemedia
Not using the add-on anymore, I'm following the guide you posted on werstnet.
mnakalay replied on at Permalink Reply
mnakalay
ok but that tutorial was about a very specific case, acting on saved attribute, which is not what you're doing anymore so I'm not sure it's going to be helpful.

Anyway, as I said, I reached the end of what I can do as I said. I have no other idea.
mnakalay replied on at Permalink Best Answer Reply
mnakalay
Finally found the problem. You can't use enterGroup with a group's name, you need a group object so you can rewrite your code like so
$group = Group::getByName('Franchise');
if(is_object($group)) {
            if(!$u->inGroup($group)){
               $u->enterGroup($group);
            }      
         }

And you probably don't really need to check if the user is already in that group but you can also keep it. The code shouldn't throw an error with or without it.