Customizing SMF > SMF Coding Discussion

Some issues with a foreach

(1/1)

Suki:
OK, been pulling my hair for a few hours with this particular issue.

I'm working on the mention stuff for Breeze, so far it works well, the problem is, it doesn't support multiple mentions.

This is my entire code:


--- Code: --- private function mention($s)
{
global $user_info, $scripturl;

$tempQuery = Breeze::quickQuery('members');
$searchNames = array();

/* Serach for all possible names */
if (preg_match_all($this->regex['mention'], $s, $matches, PREG_SET_ORDER))
foreach($matches as $m)
$querynames[] = trim($m[1]);

/* Nothing was found */
else
return $s;

/* Let's make a quick query here... */
$tempParams = array (
'rows' => 'id_member, member_name, real_name',
'where' => 'real_name IN({array_string:names}) OR member_name IN({array_string:names})',
);
$tempData = array(
'names' => array_unique($querynames),
);
$tempQuery->params($tempParams, $tempData);
$tempQuery->getData('id_member', false);

/* Get the actual users */
$searchNames = !is_array($tempQuery->dataResult()) ? array($tempQuery->dataResult()) : $tempQuery->dataResult();

reset($querynames);

/* We got some results */
if (!empty($searchNames))
{
/* You can't tag yourself */
if (array_key_exists($user_info['id'], $searchNames))
unset($searchNames[$user_info['id']]);

echo '<pre>';print_r($searchNames);echo '</pre>';

/* Lets collect the info */
foreach($querynames as $name)
{
$find[] = '{'. $name .'}';

/* is this a valid user? */
$id = BreezeTools::returnKey($name, $searchNames);

if (!empty($id))
$replace[] = '@<a href="' . $scripturl . '?action=profile;u=' . $id . '">' . $name . '</a>';

else
$replace[] = '@' .$name;
}

echo '<pre>';print_r($replace);echo '</pre>';

/* Do the replacement already */
$s = str_replace($find, $replace, $s);
}

/* There is no users, so just replace the names with a nice @ */
else
foreach($matches as $m)
$s = str_replace($m[0], '@'.$m[1], $s);

/* We are done mutilating the string, lets returning it */
return $s;
}

--- End code ---

The problem lies on  this foreach:


--- Code: --- foreach($querynames as $name)
{
$find[] = '{'. $name .'}';

/* is this a valid user? */
$id = BreezeTools::returnKey($name, $searchNames);

if (!empty($id))
$replace[] = '@<a href="' . $scripturl . '?action=profile;u=' . $id . '">' . $name . '</a>';

else
$replace[] = '@' .$name;
}

--- End code ---

this is the code for returnKey method:


--- Code: --- public static function returnKey($value, $array)
{
if (empty($value) || empty($array))
return false;

foreach ($array as $k => $v)
{
if (is_array($v))
{
if (in_array($value, $v))
return $k;

else
return false;
}

else
{
if ($v == $value)
return $k;

else
return false;
}
}
}

--- End code ---


This was actually a non static method but I converted it to an static method because I was thinking the same instance was used for all the iterations and thus, the same value was been used but it appears that was not the case.

This is a print_r for  $searchNames after unsetting the current user key


--- Code: ---Array
(
    [2] => Array
        (
            [id_member] => 2
            [member_name] => manzanita
            [real_name] => manzanita
        )

    [3] => Array
        (
            [id_member] => 3
            [member_name] => test
            [real_name] => test
        )

)

--- End code ---

and a print_r for the $replace var after the foreach iteration, $querynames is just an array with all the names the user put on the message:


--- Code: ---Array
(
    [0] => @Suki
    [1] => @Suki
    [2] => @test
    [3] => @manzanita  <-- link
)

--- End code ---

As you can see, there are 2 valid users, test and manzanita, Suki doesn't really count since it's my own account and users cannot tag themselves.  Only the manzanita user (the last item in the array) has the correct info (it was converted to a link), meaning returnKey only "works" with the last item in  $querynames even though I use a foreach and $id must take a temp value for each iteration.

Perhaps is just a silly error, dunno.  I know the error is on returnKey since if I replace that with any integer then all the items on the array gets converted since $id is not empty, thing is, I really don't know any other way to obtain the ID from the $searchNames using only the name as resource.

Suki:
OK, I solved it with this:


--- Code: --- /* We got some results */
if (!empty($searchNames))
{
/* You can't tag yourself */
if (array_key_exists($user_info['id'], $searchNames))
unset($searchNames[$user_info['id']]);

/* Lets collect the info */
foreach($searchNames as $name)
{
$find[] = '{'. $name['member_name'] .'}';

$replace[] = '@<a href="' . $scripturl . '?action=profile;u=' . $name['id_member'] . '">' . $name{'member_name'} . '</a>';
}


/* Do the replacement already */
$s = str_replace($find, $replace, $s);
}

--- End code ---

Instead of using two arrays I simply used the $searchNames array which already contains all the info I need. Downside of this is that the mention has to be exact, that is, this will not work: {suki} the user will need to type the exact name: {Suki}.

Still I have to make some fixes here and there to prevent an user from tagging another user multiple times. It also has some disadvantages, users tagging themselves will not be converted to @Suki but instead they will remain as raw semi-code: {Suki} guess I need to add yet another separated string to convert those names to @Username format of course without the link.

I also till need to move this out of the parser class, I'm pretty sure users would not want to be notified every time a message is displayed :P

Navigation

[0] Message Index

Go to full version