PDA

View Full Version : Array loop and datamanager save() problem


Gandalf-LoJ
02-12-2009, 08:43 AM
Hey all, I've stumbled across an issue that has got me totally stumped.

What I have is a script that will run via the scheduled task system that will update a users membergroups based on whether they have a particular award assigned to them. (and removes if they no longer have that award)

This was working great when it was done for a couple of awards as I simply hardcoded in the award and group id's.

Now, as there are many awards and groups to assign I modified the script and put all of the values into an array, which will then loop through that and update everyone accordingly. Sounds simple, and when I echo to screen all of the data it looks like it is working perfectly. However it is not updating everyone as per what is being displayed on the screen.

It is almost as if the
$userdm->set('membergroupids', $membergroupids);
$userdm->save();
is not saving everyone. What is really confusing is that it will for some people, but not for others.

As mentioned above, if I hard code the group and award id's it works perfectly. So it appears to be something to do with the looping of the array that is upsetting the datamanager. Just wondering if this is a limitation or just something I'm doing wrong!

I've tried several variants of looping the array from foreach, do while, and finally a simple count array and then a for loop until count. All the same result!

Below is the first half of the script that has the add users. The delete is essentially the same problem. This is the latest test with the count array and for until count option.

Here's a sample of the many echos (being very thorough!) that is produced when the script is run. The first ID user 66 is being assigned to group 50 as he has that award, but when I check the account after the script has been run it is not there even though it says it's been saved.

Any ideas at all?

18|
Award=3, Group=50
Existing Groups=27,43 | UserID=66 Membergroups=27,43,50 | Account updated! | UserID=66 Membergroups=27,43,50
Existing Groups=52 | UserID=806 Membergroups=52,50 | Account updated! | UserID=806 Membergroups=50,52
Existing Groups=37,48,50 | UserID=234 Membergroups=37,48,50 | Account updated! | UserID=234 Membergroups=37,48,50
Existing Groups=48,50 | UserID=800 Membergroups=48,50 | Account updated! | UserID=800 Membergroups=48,50


// ######################## SET PHP ENVIRONMENT ###########################
error_reporting(E_ALL & ~E_NOTICE);
if (!is_object($vbulletin->db))
{
exit;
}

// ########################### SET VARIABLES ##############################

// Awards - This controls the foreach statement and is used as the array index for $grouparr
$awardarr = array(3, 5, 6, 9, 12, 13, 14, 17, 18, 20, 21, 24, 25, 29, 31, 32, 38, 39);

// Groups - Here we have the relevant award as the index and the group that award belongs to as the value
$grouparr = array(
3 => 50,
5 => 38,
6 => 50,
9 => 53,
12 => 23,
13 => 43,
14 => 43,
17 => 51,
18 => 37,
20 => 53,
21 => 53,
24 => 53,
25 => 53,
29 => 48,
31 => 40,
32 => 39,
38 => 46,
39 => 52
);

// ################################################## ######################
// ######################### USERGROUP UPDATES ############################
// ######################### GIVE ACCESS ############################
// ################################################## ######################

foreach ($awardarr AS $key => $awardval)
{
$aw2gr = $grouparr[$awardval];
echo "<br><br>Award=".$awardval.", Group=".$aw2gr;
// check for award and update secondary usergroup if required
$giveawards = $vbulletin->db->query_read("
SELECT award_id, userid
FROM " . TABLE_PREFIX . "award_user
WHERE award_id = $awardval
");

if ($vbulletin->db->num_rows($giveawards) > 0)
{
while ($giveawardsrow = $vbulletin->db->fetch_array($giveawards))
{ // for each award, check to see if they are a member of the relevant group and update accordingly
$userdm =& datamanager_init('User', $vbulletin, ERRTYPE_ARRAY);
$userinfo = fetch_userinfo($giveawardsrow['userid']);
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo "<br>Existing Groups=".$membergroupids." | ";
if ($membergroupids != "")
{
$withcomma = "," . $aw2gr;
$trailingcomma = $aw2gr . ",";
$membergroupids = str_replace("$withcomma", "", $membergroupids);
$membergroupids = str_replace("$trailingcomma", "", $membergroupids);
$membergroupids = str_replace("$aw2gr", "", $membergroupids);
if ($membergroupids != "")
{
$membergroupids = $membergroupids . $withcomma;
}
else
{
$membergroupids = $aw2gr;
}
}
else
{
$membergroupids = $aw2gr;
}
echo "UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
$userdm->set('membergroupids', $membergroupids);
if (count($userdm->errors))
{
for($i=0; $i<count($userdm->errors); $i++)
{
echo "ERROR{$i}:{$userdm->errors[$i]}\n";
}
}
else
{
// If everything is OK
$userdm->save();
echo " | Account updated!";
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo " | UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
}
}
$vbulletin->db->free_result($giveawardsrow);
}
}

Marco van Herwaarden
02-12-2009, 08:54 AM
I think this is where you go wrong:
echo $arrsize."|";
for ($i = 1; $i <= $arrsize; $i++)
{
$awardval = $awardarr[$i-1];

$i will generate numbers from 1 to the number of entries in the array, so: 1,2,3,4,5,..

However there is not entry $awardarr[1], you only have 3, 5, 6, ....

Instead of using a for loop, why not act on the arracy directly, ie:

foreach ($awardarr AS $key => $value)
{
...process entry...
}

Gandalf-LoJ
02-12-2009, 08:59 AM
The foreach loop was my first attempt which didn't work either. It was giving exactly the same results. It looked like everything was working as the correct values were being echoed to the screen but on checking only some users were being updated.

So in theory there is nothing stopping the datamanager save command working within a loop? If not then I'll keep experimenting! So glad we're allowed a testvb install :D

Actually, just checked and my foreach was as;
foreach ($awardarr as $awardval)
{

Just trying your suggestion.

--------------- Added 1234436902 at 1234436902 ---------------

Unfortunatly same result.

There is something about the loop that it doesn't like. I'll keep digging, but figured I'd post here incase it's something I'm doing really silly.

Guest190829
02-12-2009, 09:12 AM
You should be calling pre_save() (I think that is the name of the function off the top of my head) before doing any error calling - it is there where the error array is populated.

Gandalf-LoJ
02-12-2009, 09:26 AM
You should be calling pre_save() (I think that is the name of the function off the top of my head) before doing any error calling - it is there where the error array is populated.

Thanks, I'll look into that. I never used to have the error check in there. I put that in to see if there were any occuring.

--------------- Added 1234439530 at 1234439530 ---------------

ok, getting somewhere now. It's not the loop failing as I've tried removing that part and copying the code out three times then setting the award id manually like so;

// Awards - This controls the foreach statement and is used as the array index for $grouparr
$awardarr = array(3, 5, 6, 9, 12, 13, 14, 17, 18, 20, 21, 24, 25, 29, 31, 32, 38, 39);

// Groups - Here we have the relevant award as the index and the group that award belongs to as the value
$grouparr = array(
3 => 50,
5 => 38,
6 => 50,
9 => 53,
12 => 23,
13 => 43,
14 => 43,
17 => 51,
18 => 37,
20 => 53,
21 => 53,
24 => 53,
25 => 53,
29 => 48,
31 => 40,
32 => 39,
38 => 46,
39 => 52
);

// ################################################## ######################
// ######################### USERGROUP UPDATES ############################
// ######################### GIVE ACCESS ############################
// ################################################## ######################


$awardval = 3;
$aw2gr = $grouparr[$awardval];
echo "<br><br>Award=".$awardval.", Group=".$aw2gr;
// check for award and update secondary usergroup if required
$giveawards = $vbulletin->db->query_read("
SELECT award_id, userid
FROM " . TABLE_PREFIX . "award_user
WHERE award_id = $awardval
");

if ($vbulletin->db->num_rows($giveawards) > 0)
{
while ($giveawardsrow = $vbulletin->db->fetch_array($giveawards))
{ // for each award, check to see if they are a member of the relevant group and update accordingly
$userdm =& datamanager_init('User', $vbulletin, ERRTYPE_ARRAY);
$userinfo = fetch_userinfo($giveawardsrow['userid']);
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo "<br>Existing Groups=".$membergroupids." | ";
if ($membergroupids != "")
{
$withcomma = "," . $aw2gr;
$trailingcomma = $aw2gr . ",";
$membergroupids = str_replace("$withcomma", "", $membergroupids);
$membergroupids = str_replace("$trailingcomma", "", $membergroupids);
$membergroupids = str_replace("$aw2gr", "", $membergroupids);
if ($membergroupids != "")
{
$membergroupids = $membergroupids . $withcomma;
}
else
{
$membergroupids = $aw2gr;
}
}
else
{
$membergroupids = $aw2gr;
}
echo "UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
$userdm->set('membergroupids', $membergroupids);
$userdm->pre_save();
if (count($userdm->errors))
{
for ($i = 0; $i < count($userdm->errors); $i++)
{
echo "ERROR{$i}:{$userdm->errors[$i]}\n";
}
}
else
{
// If everything is OK
$userdm->save();
echo " | Account updated!";
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo " | UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
}
}
$vbulletin->db->free_result($giveawardsrow);
}



$awardval = 5;
$aw2gr = $grouparr[$awardval];
echo "<br><br>Award=".$awardval.", Group=".$aw2gr;
// check for award and update secondary usergroup if required
$giveawards = $vbulletin->db->query_read("
SELECT award_id, userid
FROM " . TABLE_PREFIX . "award_user
WHERE award_id = $awardval
");

if ($vbulletin->db->num_rows($giveawards) > 0)
{
while ($giveawardsrow = $vbulletin->db->fetch_array($giveawards))
{ // for each award, check to see if they are a member of the relevant group and update accordingly
$userdm =& datamanager_init('User', $vbulletin, ERRTYPE_ARRAY);
$userinfo = fetch_userinfo($giveawardsrow['userid']);
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo "<br>Existing Groups=".$membergroupids." | ";
if ($membergroupids != "")
{
$withcomma = "," . $aw2gr;
$trailingcomma = $aw2gr . ",";
$membergroupids = str_replace("$withcomma", "", $membergroupids);
$membergroupids = str_replace("$trailingcomma", "", $membergroupids);
$membergroupids = str_replace("$aw2gr", "", $membergroupids);
if ($membergroupids != "")
{
$membergroupids = $membergroupids . $withcomma;
}
else
{
$membergroupids = $aw2gr;
}
}
else
{
$membergroupids = $aw2gr;
}
echo "UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
$userdm->set('membergroupids', $membergroupids);
$userdm->pre_save();
if (count($userdm->errors))
{
for ($i = 0; $i < count($userdm->errors); $i++)
{
echo "ERROR{$i}:{$userdm->errors[$i]}\n";
}
}
else
{
// If everything is OK
$userdm->save();
echo " | Account updated!";
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo " | UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
}
}
$vbulletin->db->free_result($giveawardsrow);
}



$awardval = 9;
$aw2gr = $grouparr[$awardval];
echo "<br><br>Award=".$awardval.", Group=".$aw2gr;
// check for award and update secondary usergroup if required
$giveawards = $vbulletin->db->query_read("
SELECT award_id, userid
FROM " . TABLE_PREFIX . "award_user
WHERE award_id = $awardval
");

if ($vbulletin->db->num_rows($giveawards) > 0)
{
while ($giveawardsrow = $vbulletin->db->fetch_array($giveawards))
{ // for each award, check to see if they are a member of the relevant group and update accordingly
$userdm =& datamanager_init('User', $vbulletin, ERRTYPE_ARRAY);
$userinfo = fetch_userinfo($giveawardsrow['userid']);
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo "<br>Existing Groups=".$membergroupids." | ";
if ($membergroupids != "")
{
$withcomma = "," . $aw2gr;
$trailingcomma = $aw2gr . ",";
$membergroupids = str_replace("$withcomma", "", $membergroupids);
$membergroupids = str_replace("$trailingcomma", "", $membergroupids);
$membergroupids = str_replace("$aw2gr", "", $membergroupids);
if ($membergroupids != "")
{
$membergroupids = $membergroupids . $withcomma;
}
else
{
$membergroupids = $aw2gr;
}
}
else
{
$membergroupids = $aw2gr;
}
echo "UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
$userdm->set('membergroupids', $membergroupids);
$userdm->pre_save();
if (count($userdm->errors))
{
for ($i = 0; $i < count($userdm->errors); $i++)
{
echo "ERROR{$i}:{$userdm->errors[$i]}\n";
}
}
else
{
// If everything is OK
$userdm->save();
echo " | Account updated!";
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo " | UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
}
}
$vbulletin->db->free_result($giveawardsrow);
}

It runs fine and everything echos correctly however only the members in the very first segment get their groups set. The following two (award ids 5 and 9) are ignored even though the queries do run as proved by the correct data being echoed to screen.

--------------- Added 1234442124 at 1234442124 ---------------

ok, it's the arrays at the top thats causing the problem.

A follow on from the 'three stage' test that I done still referenced one array.

I commented out the following line at the beginning of each step like so;
//$aw2gr = $grouparr[$awardval];

and hardcoded the value to each one like so;
$aw2gr = 50;

and it all works perfectly.

Looks like I need to do some more reading on arrays which I've not used in php too much.

Finally getting somewhere!

Marco van Herwaarden
02-12-2009, 11:06 AM
$aw2gr = $grouparr[$awardval];

What data are you trying to lookup in the $grouparr array? I have the feeling that you don't need that array at all as it seems you are trying to use the same value that is already available as $key.

Gandalf-LoJ
02-12-2009, 11:24 AM
$aw2gr = $grouparr[$awardval];

What data are you trying to lookup in the $grouparr array? I have the feeling that you don't need that array at all as it seems you are trying to use the same value that is already available as $key.

The data that I'm checking for is the vb usergroup ID

the $grouparr is set with the key being the relevant award ID and the value is the vb usergroup ID that needs to be assigned to the user in question.

I see what you're saying though. With that in mind I now have;
$arr = array (
3 => 50,
5 => 38,
6 => 50,
9 => 53,
12 => 23,
13 => 43,
14 => 43,
17 => 51,
18 => 37,
20 => 53,
21 => 53,
24 => 53,
25 => 53,
29 => 48,
31 => 40,
32 => 39,
38 => 46,
39 => 52
);

// ################################################## ######################
// ######################### USERGROUP UPDATES ############################
// ######################### GIVE ACCESS ############################
// ################################################## ######################

foreach ($arr as $key => $val)
{
echo "<br><br>Award=".$key.", Group=".$val;
// check for award and update secondary usergroup if required
$giveawards = $vbulletin->db->query_read("
SELECT award_id, userid
FROM " . TABLE_PREFIX . "award_user
WHERE award_id = $key
");

if ($vbulletin->db->num_rows($giveawards) > 0)
{
while ($giveawardsrow = $vbulletin->db->fetch_array($giveawards))
{ // for each award, check to see if they are a member of the relevant group and update accordingly
$userdm =& datamanager_init('User', $vbulletin, ERRTYPE_ARRAY);
$userinfo = fetch_userinfo($giveawardsrow['userid']);
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo "<br>Existing Groups=".$membergroupids." | ";
if ($membergroupids != "")
{
$withcomma = "," . $val;
$trailingcomma = $val . ",";
$membergroupids = str_replace("$withcomma", "", $membergroupids);
$membergroupids = str_replace("$trailingcomma", "", $membergroupids);
$membergroupids = str_replace("$val", "", $membergroupids);
if ($membergroupids != "")
{
$membergroupids = $membergroupids . $withcomma;
}
else
{
$membergroupids = $val;
}
}
else
{
$membergroupids = $val;
}
echo "UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
$userdm->set('membergroupids', $membergroupids);
$userdm->pre_save();
if (count($userdm->errors))
{
for ($i = 0; $i < count($userdm->errors); $i++)
{
echo "ERROR{$i}:{$userdm->errors[$i]}\n";
}
}
else
{
// If everything is OK
$userdm->save();
echo " | Account updated!";
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo " | UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
}
}
$vbulletin->db->free_result($giveawardsrow);
}
}

It runs, and everything echos out perfectly to the screen. They're just not being updated! The only difference between this code and the copy, paste however many times and hardcode values, is the array.

Marco van Herwaarden
02-12-2009, 11:54 AM
Instead of doing all the str_replace's on the membergroupids, why not explode it to an array, manipulate and implode back again.

Ie. something like:

// Explode to an array
$mbrgrp_array = explode(",", $membergroupids);

// Add remove/add group to array
....code here...

// Make it a comma seperated string again
$membergroupids = implode(",", $mbrgrp_array);


Just trying to simplify your code first as that makes it easier to troubleshoot.

Gandalf-LoJ
02-12-2009, 12:22 PM
Instead of doing all the str_replace's on the membergroupids, why not explode it to an array, manipulate and implode back again.

Ie. something like:

// Explode to an array
$mbrgrp_array = explode(",", $membergroupids);

// Add remove/add group to array
....code here...

// Make it a comma seperated string again
$membergroupids = implode(",", $mbrgrp_array);


Just trying to simplify your code first as that makes it easier to troubleshoot.

Thanks, didn't think of that! Does make it neater. Added and looks good on the echoed data but it's still not happy with saving the data.

--------------- Added 1234453404 at 1234453404 ---------------

ok, struggling with this and I think it's either because of the amount of updates or the length of the script.

I've blocked it out as explained above and set the group id's manually for each block and it works fine upto a point. Once I get to four blocks it stops working, even though the echo to screen is fine.

I'm sure this is what is happening with the array loop too. Are there any limitations to the schedule tasks at all?

--------------- Added 1234453821 at 1234453821 ---------------

just confirmed. Added the array loop back in with a much shorter array (two entries) and it runs perfectly.

So I'm guessing the amount of updates that the script is trying to do is overwhelming something. But what, the datamanager? or the server? There are no errors showing in the error log at all.

<?php

// ######################## SET PHP ENVIRONMENT ###########################
error_reporting(E_ALL & ~E_NOTICE);
if (!is_object($vbulletin->db))
{
exit;
}

// ########################### SET VARIABLES ##############################

$arr = array(
3 => 50,
5 => 38
);

// ################################################## ######################
// ######################### USERGROUP UPDATES ############################
// ######################### GIVE ACCESS ############################
// ################################################## ######################

foreach ($arr as $awardval => $aw2gr)
{
//$awardval = 3; $aw2gr = 50;
//$aw2gr = $grouparr[$awardval];
echo "<br><br>Award=".$awardval.", Group=".$aw2gr;
// check for award and update secondary usergroup if required
$giveawards = $vbulletin->db->query_read("
SELECT award_id, userid
FROM " . TABLE_PREFIX . "award_user
WHERE award_id = $awardval
");

if ($vbulletin->db->num_rows($giveawards) > 0)
{
while ($giveawardsrow = $vbulletin->db->fetch_array($giveawards))
{ // for each award, check to see if they are a member of the relevant group and update accordingly
$userdm =& datamanager_init('User', $vbulletin, ERRTYPE_ARRAY);
$userinfo = fetch_userinfo($giveawardsrow['userid']);
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo "<br>Existing Groups=".$membergroupids." | ";
if ($membergroupids != "")
{
// Explode to an array
$mbrgrp_array = explode(",", $membergroupids);
// Add remove/add group to array
$mbrgrp_array[] = $aw2gr;
// Make it a comma seperated string again
$membergroupids = implode(",", $mbrgrp_array);
}
else
{
$membergroupids = $aw2gr;
}
echo "UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
$userdm->set('membergroupids', $membergroupids);
$userdm->pre_save();
if (count($userdm->errors))
{
for ($i = 0; $i < count($userdm->errors); $i++)
{
echo "ERROR{$i}:{$userdm->errors[$i]}\n";
}
}
else
{
// If everything is OK
$userdm->save();
echo " | Account updated!";
$userdm->set_existing($userinfo);
$membergroupids = $userdm->fetch_field('membergroupids');
echo " | UserID=".$giveawardsrow['userid']." Membergroups=".$membergroupids;
unset($mbrgrp_array);
}
}
$vbulletin->db->free_result($giveawardsrow);
}
}

unset($giveawards, $giveawardsrow, $userdm, $userinfo, $membergroupids, $awardval, $aw2gr, $mbrgrp_array);

log_cron_action('', $nextitem, 1);
?>

--------------- Added 1234456496 at 1234456496 ---------------

/facepalm!

I am so dumb! Solved it!

ok, so this is to be a scheduled task that updates users membergroups. However, if they're already a member then there is no reason to do anything with them.

However, I totally neglected to take this into account with the query!

So, give awards query becomes;
$giveawards = $vbulletin->db->query_read("
SELECT aw.award_id, us.userid, us.membergroupids
FROM " . TABLE_PREFIX . "award_user as aw
LEFT OUTER JOIN " . TABLE_PREFIX . "user AS us ON us.userid = aw.userid AND (aw.award_id = $awardval)
WHERE FIND_IN_SET($aw2gr, us.membergroupids) = 0
");

and now it works perfectly with a full array :o

well, it's been a fun afternoon, please don't laugh at me too much! :D