Problem with trying to get user attributes

Permalink
I have set up my site so that there is code that gets called when a user registers. The code sends an email to the user saying their registration is pending activation by the admin once payment is received. This is all working great but now client wants this email to be more of an invoice so it needs some user fields that were entered on registration.

The problem is that I cannot seem to grab user attributes other than userName and userEmail (no error but nothing is returned). Could this be because the user is not yet activated? As a quick test, I used the same code and grabbed attributes from the admin user and everything worked.

I am making various calls like this using the dynamic methods that get generated based on the attribute name (e.g. attribute is this example is Lastname):
$lastname = $ui->getUserLastname();


Does anyone have any ideas? I looked at the code in userinfo and I couldn't see any test to check if user is active. I have really been struggling trying to get this to work so if you have any suggestions, I'd appreciate it.

 
RadiantWeb replied on at Permalink Reply
RadiantWeb
I created my own function that pulls all attributes from the table UserAttributeValues, then goes and grabs from AttributeKeys where the akID = akID...then puts matches into an array. then I run a loop for each key name set to VAR = value. sounds more complex than it is. lol

there is probably an easier way to do it...but that totally worked for me ;-P
RadiantWeb replied on at Permalink Reply
RadiantWeb
function getPosterInfo($uID){
         $db = Loader::db();
         $g = $db->Execute("SELECT * FROM UserAttributeValues WHERE uID= '$uID' ");
            while ($grow = $g->fetchrow()){
               $avID = $grow['avID'];
               $avKey = $grow['akID'];
               $v = $db->Execute("SELECT akName FROM AttributeKeys WHERE akID= '$avKey ' ");
               while ($vrow = $v->fetchrow()){
               $name= $vrow['akName'];
               }
               $s = $db->Execute("SELECT value FROM atDefault WHERE avID= '$avID' ");
               while ($srow = $s->fetchrow()){
               $value = $srow['value'];
               }
               //$infoArray[] = ($name,$value);
RadiantWeb replied on at Permalink Reply
RadiantWeb
that will get you an array of all things user that looks like this:

$uName => uName_Value
$uEmail => uEmail_value
$uCustom1 => uCustom1_value
$uCustom2 => uCustom2_value

ect..
Tony replied on at Permalink Reply
Tony
no offense to chad, but i wouldn't really recommend any approach where you're having to type sql.

if anything, this should be the long form way of doing it approach:
$attrHandle = 'your_attribute_key_handle';
$attrKey = UserAttributeKey::getByHandle( $attrHandle );
if( !is_object($attrKey) ) continue; 
$keyName = $attrKey->getAttributeKeyName();
$attrVal = $userInfo->getAttribute($attrKey->getAttributeKeyHandle());


you can also try:
$ui->getAttribute('your_attribute_key_handle');


a couple of things to watch out for 1) make sure your attribute key handle is correct & that you're not using the attribute key name by accident, and 2) sometimes it's easy to confuse functionality of the userinfo class with the user class (their tricky autoloader stuff suppresses errors in a bad way in my opinion).
RadiantWeb replied on at Permalink Reply
RadiantWeb
well, I needed to sql it to get all of them in my case. if you have a more global way to grab them all...please enlighten ;-D
Tony replied on at Permalink Reply
Tony
chad, i think you could probably do something like this:
$attributeKeys = AttributeType::getList()
foreach($attributeKeys as $ak){
  echo $ui->getAttribute($ak->getAttributeKeyHandle);
}


the main reason why direct sql aren't such a good idea in most cases (besides more complicated code), is so if the data structure changes on later versions of concrete, your code is much more likely to stay backwards compatible.
RadiantWeb replied on at Permalink Reply
RadiantWeb
I'll try that. thank you.
dg1 replied on at Permalink Reply
Thanks for your help. Unfortunately, I still can't get it to work. I tried both methods mentioned by Tony but still nothing is returned. I finally added some logging code to the getAttribute function in userinfo.php as follows:
public function getAttribute($ak, $displayMode = false) {
         Loader::model('attribute/categories/user');
         if (!is_object($ak)) {
UserInfo::logToFile("dgtest.log", "getAttribute handle:". $ak); 
            $ak = UserAttributeKey::getByHandle($ak);
         }
         if (is_object($ak)) {
            $av = $this->getAttributeValueObject($ak);
            if (is_object($av)) {
UserInfo::logToFile("dgtest.log", "getAttribute " . $av->getValue($displayMode));
               return $av->getValue($displayMode);
            }
                                else { UserInfo::logToFile("dgtest.log", "getAttribute: av not an object??"); }
         }
                        else {


My logging shows the following is happening:

[2010/02/16 02:04:28] getAttribute handle:firstname
[2010/02/16 02:04:28] getAttribute: av not an object??
[2010/02/16 02:04:28] getAttribute handle:lastname
[2010/02/16 02:04:28] getAttribute: av not an object??
[2010/02/16 02:04:28] getAttribute handle:employer
[2010/02/16 02:04:28] getAttribute: av not an object??

Again, could this be from the user not being activated? It looks like "av" is not an object so nothing gets returned. Could this be a bug?

I thought getting the attributes would be such an easy thing to accomplish but no such luck in this case (works fine for me elsewhere).

Thanks.
Tony replied on at Permalink Reply
Tony
good job on trying to trace what's happening here.

first, go to the dashboard and clear your cache. then try again.

second, are you sure that user has a value for that attribute? if so, then if i were you i'd continue tracing the code into $this->getAttributeValueObject($ak); to see what it can't load the value.
dg1 replied on at Permalink Reply
I did go ahead and add more logging code to userinfo.php method getAttributeValueObject and found something interesting. This code does a query to select avID from UserAttributeValues where uID= and akID=. I dumped out uID and akID and they are correct and I do see that the database entry is there but nothing is returned for avID causing nothing to get returned in the getAttribute call.

I think I may be hitting a race condition during user add. I should mention that my code is a handler for the event on_user_add. I am wondering if the event is getting fired before the user is fully set up? By the time I look at the database, the entries are there but it looks like they weren't there when the event was fired.

Does it sound like I am on the right track? I have already spent hours on what I thought would take a few minutes so I am getting very discouraged.
dg1 replied on at Permalink Reply
Well, I think I am SOL. I looked at the code in controllers/register.php. It looks like the attributes don't get saved until after the user is added so I think that is my problem. It appears that the on_user_add event is fired before everything is really fully set up.

Here is the code:
// do the registration
         $data = $_POST;
         $data['uName'] = $username;
         $data['uPassword'] = $password;
         $data['uPasswordConfirm'] = $passwordConfirm;
         $process = UserInfo::register($data);
         if (is_object($process)) {
            foreach($aks as $uak) {
               $uak->saveAttributeForm($process);


The register call does the add which fires the event and then after that, saveAttributeForm is called.
dg1 replied on at Permalink Reply
I moved my code into do_register after the attributes get saved as shown in my previous post (controllers/register.php) and now everything works. It would be cleaner to have my code in the on_user_add event handler but at least now I know what the problem is.

Thanks for your help Tony and Chad.
hockeyshooter replied on at Permalink Reply
hockeyshooter
URGENT!

I too was using SQL on the old UserAttributeValues table to get my custom user fields, but switching to the following does not work:

$ui = UserInfo::getByID($uId);
$cName=$ui->getAttribute('realname');


If I dump the whole of $ui, I don't see any of my custom fields - what's going on?
tash replied on at Permalink Reply
tash
can you tell me what you added, and where? I'm trying to get a user attribute whose handle is 'first_name' on_user_add. But, as you mentioned before, it looks like I can't grab the attribute in my case b/c the on_user_add event is fired before everything is really fully setup.

help please =\
dg1 replied on at Permalink Reply
As I mentioned above, I ended up retrieving the attributes in the do_register function in controllers/register.php (make your own copy so you don't blow away the one in the concrete directory).

It's been awhile since I looked at the code, but I believe the attributes get saved by the call $uak->saveAttributeForm($process) so you have to add your code after this call.

I added my code after the check for whether or not registration approval is required as shown below:

} else if(defined('USER_REGISTRATION_APPROVAL_REQUIRED') && USER_REGISTRATION_APPROVAL_REQUIRED) {
$ui = UserInfo::getByID($u->getUserID());
$ui->deactivate();

// CUSTOM CODE: Send user confirmation email with user attributes
$mh2 = Loader::helper('mail');
$mh2->addParameter('userFirstname', $ui->getAttribute('firstname'));
$mh2->addParameter('userLastname', $ui->getUserLastname());
$mh2->addParameter('userEmployer', $ui->getAttribute('college_institution'));

etc....
tash replied on at Permalink Reply
tash
Thanks. I wonder if this is going to work for me. Right now, I'm creating a new page on user add. So, I have this in my config/site_events.php file

Events::extend('on_user_add', 'AddUserPage', 'userPageAdd', 'models/application_user.php');

and in my application_user.php file:


class AddUserPage extends Object
{
public function userPageAdd($ui) {
//all my code
//wish I could grab the user attribs here
}
}

I can't nest a class in register.php, do you know how I could create my page on_user_add and grab the new user's attributes all in the same process?

Here's my application_user.php file:http://pastie.org/1230249 ignore lines 16 and 17
rpagat1 replied on at Permalink Reply
hi tash, I would suggest that you create a new event which will be called/fired after registration is successful. To accomplish this, update controllers/register.php. In the code below, I am firing a new even "on_user_add_after" when registration is successful and all the user attributes are available in the UserInfo.

$registerData['success']=1;
//5-Jul-2011 Rey: fire event when registration is successful
$ui = UserInfo::getByID($registerData['uID']);
Events::fire('on_user_add_after', $ui);
gabrielkolbe replied on at Permalink Reply
I did this..
function getUserAttributes($uID){
                     $userattributesarray = array();
                     $usernames = array();
                     $uservalues = array();
                        $db = Loader::db();
                         $q  = "SELECT AK.akName, aD.value 
                                FROM UserAttributeValues UAV
                                JOIN AttributeKeys AK  
                                ON UAV.akID = AK.akid
                                JOIN atDefault aD
                                ON UAV.avID = aD.avID
                                WHERE UAV.uID= '$uID' ";
                        $g = $db->Execute($q);
                            while ($grow = $g->fetchrow()){
                            array_push($usernames, $grow['akName']);


then call it like this

$u = new User();

$useratts = $u->getUserAttributes($_SESSION['uID']);

actually let me post I used it to autofill the 'shipping' details to the 'billing' details here is it have fun..

<form id="addressform">
<?PHP
$u = new User();
$useratts = $u->getUserAttributes($_SESSION['uID']);
?>
<div id="billing_fields">
   <input type="hidden" name="House" id="House" value="<?PHP print $useratts[House]; ?>">
   <input type="hidden" name="Street" id="Street" value="<?PHP print $useratts[Street]; ?>">
   <input type="hidden" name="Town" id="Town" value="<?PHP print $useratts[Town]; ?>">
   <input type="hidden" name="Country" id="Country" value="<?PHP print $useratts[Country]; ?>">
   <input type="hidden" name="Postcode" id="Postcode" value="<?PHP print $useratts[Postcode]; ?>">
</div>
                <h3>Billing Details</h3>
               <table cellspacing="0">
                   <tr>
gabrielkolbe replied on at Permalink Reply
the function getUserAttributes($uID); I insert in the user model which I checked out of the concrete library.