Code snippets, tech tricks and other bits and bobs

Bugfix: JomSocial - Group Invitations don't send

Jomsocial 2.2 for Joomla!

Symptom:

When clicking Send Invitations, nothing happens

Cause:

AJAX request returns a Joomla! 500 Internal Server Error:

DB function failed with error number 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '`creator`='67' WHERE `groupid`='97' AND `userid`='5417'' at line 1
SQL=UPDATE `jos_community_groups_invite` SET `groupid`='97', `userid`='5417' `creator`='67' WHERE `groupid`='97' AND `userid`='5417'

This is an obvious and very basic SQL syntax error - there is no comma after `userid`='5417'

JomSocial's AJAX error handling is... somewhat lacking - it simply fails to respond to most errors, including the dreaded 'Invalid Token' Joomla! error, meaning the user has no idea that an error has even occurred, and leaving them ill equipped to report problems.

Solution:

components\com_community\tables\groupinvite.php

89c89
<                     . $db->nameQuote( 'userid' ) . '=' . $db->Quote( $this->userid ) . ' '
---
>                     . $db->nameQuote( 'userid' ) . '=' . $db->Quote( $this->userid ) . ',' 

(Unix diff formatting)

Filed under  //   JomSocial   Joomla!   MySQL   PHP  

JomSocial - HWDVideoShare activity feed filter

Symptom:

We have a Joomla/JomSocial installation with HWDVideoShare component and the Activity Filter plugin. I have hacked the 'video' activity filter to display the HWDVideoShare activities in the feed instead of the default JomSocial video activities.

Clicking on the filter causes an AJAX request which returns 500 (Internal Server Error).
With error reporting turned on it returns 400 (OK) but with the following error message:

Fatal error: Call to undefined method JDocumentRAW::addCustomTag() in /{path}/{to}/{domain}/components/com_hwdvideoshare/hwdvideoshare.class.php on line 1739

Cause:

An AJAX call returns a raw document type, as it's not properly formatted HTML - often not even HTML at all
HWD weren't counting on their data being requested in quite this way it would seem, so when a document was created by their component, they called a function that doesn't exist for RAW documents
Surprising it didn't cause a problem for the main stream though

Solution:

components\com_hwdvideoshare\hwdvideoshare.class.php

1739c1739,1741


<                     $doc->addCustomTag(" <script type="text/javascript">// <![CDATA[ function roll_over(img_name, img_src) { document[img_name].src = img_src; } // ]]></script> <script type='text/javascript'>function roll_over(img_name, img_src) { document[img_name].src = img_src; }</script>");


---
>                     if($doc->getType() != 'raw'){
>                         $doc->addCustomTag(" <script type="text/javascript">// <![CDATA[ function roll_over(img_name, img_src) { document[img_name].src = img_src; } // ]]></script> <script type='text/javascript'>function roll_over(img_name, img_src) { document[img_name].src = img_src; }</script>");
>                     } 

(Unix diff formatting)

The end effect is cutting out a javascript rollover which isn't really necessary for the stream.

Resource:

Google Groups : Joomla! General Development - "Call to undefined method JDocumentRAW::addCustomTag()" while writing plugin [new window]

Filed under  //   AJAX   Document Type   HWDVideoShare   JomSocial   Joomla!   PHP   plg_activityfilter  

Socialcode Activity Comment 2.2 plugin for Jomsocial - Like activity error 505 fix

I’ve got a lot of unpleasant things to say about 3rd party Joomla developers. And this is an example of why.

In Socialcode’s Activity Comment plugin for JomSocial (plg_activitycomment), when you unlike an activity, it appears to work. However, what it does is remove the likes-holder div immediately with Javascript (jQuery in fact), delete the like item from the database, then throw a 505 Internal Server Error. At this point you are supposed to get a response with the new string of likes, as other people may still like the activity, but these won’t be displayed until you refresh the page.

Most people probably don’t even realise it’s broken, as unless you have FireBugs console or net panels open, you get no notification of the error.

The problem occurs because the likeitem() function requires helper functions from a separate file, which the coders failed to include. So it’s remarkably easy to fix, once you work this out, simply add the line

require_once( JPATH_PLUGINS.DS.'community'.DS.'activitycomment'.DS.'helper.php');

to the function in /plugins/community/activitycomment.php, which will now look like this:

function unlikeitem($response, $id , $userid )
{
    $my=& CFactory::getUser();
    JPlugin::loadLanguage( 'plg_activitycomment', JPATH_ADMINISTRATOR );
    if($my->id == $userid )
    {
        $db =& JFactory::getDBO();
        $query ='delete from #__activitylikes where userid=' .$db->Quote($my->id) . ' and activityid=' . $db->Quote($id);
        $db->setQuery($query);
        $db->query();

        // Check if there are other likes
        $query = 'select count(*) from #__activitylikes where activityid=' . $db->Quote($id);
        $db->setQuery($query);
        $rows = $db->loadResult();

        require_once( JPATH_PLUGINS.DS.'community'.DS.'activitycomment'.DS.'helper.php');

        if( $rows == 0 )
        {
            $response->addScriptCall(ActivityComments::getjs() ."('#likes-holder-" . $id . "').removeClass('likes-content');");
        }
        $response->addScriptCall(ActivityComments::getjs() ."('#likes-holder-" . $id . "').children().remove();");

        $text = $this->rebuildItemString( $id );
        $response->addScriptCall('activityInsertLike', $id , $text);

        return $response->sendResponse();
    }
}

I discovered this problem while updating my hacks to include a dislike button at the request of a client who’s community members wanted it. If you are interested in having the hack for your own JomSocial site, leave a comment and I’ll get in touch.

Filed under  //   Activity Comment Plugin   JomSocial   Joomla!   PHP   Socialcode  

PHP: Sort an array of objects by an object property

I was asked if it was possible to re-order the list of friends when inviting people to events in the JomSocial v.1.8.3 community component of Joomla! 1.5

The problem here was that the array of friends is an array of objects, ordered by their database id as they were pulled from the database. I don’t want to be hacking the core functions that pulled the data from the database and re-ordering it there – I want to keep as close to the top layer as possible with simple bits of code, as I don’t want to waste time decoding other peoples work.

This all occurs in /components/com_community/views/events/view.html.php

If you know JomSocial, you might be aware that the friends model function ‘getFriends’ call looks like this: /components/com_community/models/friends.php

L.855

function & getFriends($id, $sorted = 'latest', $useLimit = true , $filter = 'all' , $maxLimit = 0 )

Well, that might suggest that we can order it by changing the call in view.html.php which currently is:

L.247

$tmpFriends = $friendsModel->getFriends( $my->id , 'name' , false);

However swapping out ‘name’ for ‘username’ doesn’t work as rather than simply using this flag as the ORDER BY clause in the MySQL, the getFriends function uses a switch case to determine what action to take. models/friends.php

L.1030

switch($sorted)
{
        // We only want the id since we use CFactory::getUser later to get their full details.
        case 'online':                      
$query  .= ' ORDER BY online DESC';
                break;
        case 'suggestion':
$query  .=  ' GROUP BY (b.`connect_to`)'
        . ' HAVING (totalFriends >= ' . FRIEND_SUGGESTION_LEVEL . ')';

                break;
        case 'name':
        //sort by name only applicable to filter is not mutual and suggestion
        if($filter != 'mutual' && $filter != 'suggestion')
$query  .= ' ORDER BY b.name ASC';
break;  
        default:
$query  .= ' ORDER BY a.connection_id DESC';
                break;
}

Now I could just add a case for ‘username’ here. This would be the logical long term solution to any system over which I had real control. However, JomSocial is frequently updated, meaning any hacks I make must be reapplied, with no guarantee that they won’t have to be completely re-written. So this solution would mean changing two files, and getting deeper into the system. I want to keep my changes as few and as contiguous as possible.

Which brings me back to the original problem, and the ostensible perverse way of going about solving it.

So, I have an array of objects in the wrong order. What I’m going to do is loop through that single-dimension array, turning it into a two-dimensional array – one key the object (itself multi-dimensional), and the other key the username that we will sort on, obtained with the getDisplayName() method of the object. This new array will then be sorted with uname() and a simple custom function compare_uname($a, $b), and the sorted array looped to recreate the original single-dimensional array in the desired order. For JomSocial, this has been inserted in views/events/view.html.php at line 265

$i=0;
foreach($friends as $friend){
    $sort_friends[$i]['object'] = $friend;
    $sort_friends[$i]['uname'] = $friend->getDisplayName();
    $i++;
}
function compare_uname($a, $b){
    return strnatcmp($a['uname'], $b['uname']);
}
usort($sort_friends, 'compare_uname');
unset($friends);
foreach($sort_friends as $friend){
    $friends[] = $friend['object'];
}

Filed under  //   JomSocial   Joomla   PHP