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):
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.
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.
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);
Viewing 15 lines of 27 lines. View entire code block.
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..
$uName => uName_Value
$uEmail => uEmail_value
$uCustom1 => uCustom1_value
$uCustom2 => uCustom2_value
ect..
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:
you can also try:
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).
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).
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
chad, i think you could probably do something like this:
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.
$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.
I'll try that. thank you.
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:
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.
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 {
Viewing 15 lines of 18 lines. View entire code block.
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.
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.
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.
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.
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.
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:
The register call does the add which fires the event and then after that, saveAttributeForm is called.
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.
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.
Thanks for your help Tony and Chad.
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:
If I dump the whole of $ui, I don't see any of my custom fields - what's going on?
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?
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 =\
help please =\
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....
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....
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
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
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);
I did this..
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..
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']);
Viewing 15 lines of 20 lines. View entire code block.
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>
Viewing 15 lines of 76 lines. View entire code block.
the function getUserAttributes($uID); I insert in the user model which I checked out of the concrete library.
there is probably an easier way to do it...but that totally worked for me ;-P