Creating Joomla user profile plug-in
Asked Answered
P

4

7

I've taken a direct clone of the User Profile plug-in for my Joomla 2.5.9 install.

I've renamed the plugin and the files accordingly to 'profiletest' similar to the old 1.6 tutorial.

I've added a new input to the form and everything works on the backend and the new entry shows up as expected in the registration form on the front end. However when you register I never see the #__user_profiles table updated.

Lots of code here but it's a copy of the User profile plug-in (/plugins/user/profile/). Here is the profiletest.php onUserAfterSave function:

function onUserAfterSave($data, $isNew, $result, $error)
{
    $userId = JArrayHelper::getValue($data, 'id', 0, 'int');


    if ($userId && $result && isset($data['profiletest']) && (count($data['profiletest'])))
    {
        try
        {
            //Sanitize the date
            if (!empty($data['profiletest']['dob']))
            {
                $date = new JDate($data['profiletest']['dob']);
                $data['profiletest']['dob'] = $date->format('Y-m-d');
            }

            $db = JFactory::getDbo();
            $db->setQuery(
                'DELETE FROM #__user_profiles WHERE user_id = '.$userId .
                " AND profile_key LIKE 'profiletest.%'"
            );

            if (!$db->query())
            {
                throw new Exception($db->getErrorMsg());
            }

            $tuples = array();
            $order  = 1;

            foreach ($data['profiletest'] as $k => $v)
            {
                $tuples[] = '('.$userId.', '.$db->quote('profiletest.'.$k).', '.$db->quote(json_encode($v)).', '.$order++.')';
            }

            $db->setQuery('INSERT INTO #__user_profiles VALUES '.implode(', ', $tuples));

            if (!$db->query())
            {
                throw new Exception($db->getErrorMsg());
            }

        }
        catch (JException $e)
        {
            $this->_subject->setError($e->getMessage());
            return false;
        }
    }

    return true;
}

It never inserts anything into the DB because it never goes into this if statement:

if ($userId && $result && isset($data['profiletest']) && (count($data['profiletest'])))

Basically this condition fails: $data['profiletest']

Seems pretty basic as all I've changed in the plugin is 'profile' to 'profiletest'. However to solve this I think you need to see what my other function called onContentPrepareData. Although again it is not doing anything different other than the name change. Sorry for the long dump.

function onContentPrepareData($context, $data)
{
    // Check we are manipulating a valid form.
    if (!in_array($context, array('com_users.profile', 'com_users.user', 'com_users.registration', 'com_admin.profile')))
    {
        return true;
    }

    if (is_object($data))
    {
        $userId = isset($data->id) ? $data->id : 0;
        JLog::add('Do I get into onContentPrepareData?');


        if (!isset($data->profiletest) and $userId > 0)
        {

            // Load the profile data from the database.
            $db = JFactory::getDbo();
            $db->setQuery(
                'SELECT profile_key, profile_value FROM #__user_profiles' .
                ' WHERE user_id = '.(int) $userId." AND profile_key LIKE 'profiletest.%'" .
                ' ORDER BY ordering'
            );
            $results = $db->loadRowList();
            JLog::add('Do I get sql result: '.$results);
            // Check for a database error.
            if ($db->getErrorNum())
            {
                $this->_subject->setError($db->getErrorMsg());
                return false;
            }

            // Merge the profile data.
            $data->profiletest= array();

            foreach ($results as $v)
            {
                $k = str_replace('profiletest.', '', $v[0]);
                $data->profiletest[$k] = json_decode($v[1], true);
                if ($data->profiletest[$k] === null)
                {
                    $data->profiletest[$k] = $v[1];
                }
            }
        }

        if (!JHtml::isRegistered('users.url'))
        {
            JHtml::register('users.url', array(__CLASS__, 'url'));
        }
        if (!JHtml::isRegistered('users.calendar'))
        {
            JHtml::register('users.calendar', array(__CLASS__, 'calendar'));
        }
        if (!JHtml::isRegistered('users.tos'))
        {
            JHtml::register('users.tos', array(__CLASS__, 'tos'));
        }
    }

    return true;
}

Again I notice I never get in here:

if (!isset($data->profiletest) and $userId > 0)

Which probably affects the onUserAfterSave function.

EDIT Here is the function onContentPrepareForm:

function onContentPrepareForm($form, $data)
{
    if (!($form instanceof JForm))
    {
        $this->_subject->setError('JERROR_NOT_A_FORM');
        return false;
    }

    // Check we are manipulating a valid form.
    $name = $form->getName();
    if (!in_array($name, array('com_admin.profile', 'com_users.user', 'com_users.profile', 'com_users.registration')))
    {
        return true;
    }

    // Add the registration fields to the form.
    JForm::addFormPath(dirname(__FILE__) . '/profiles');
    $form->loadFile('profile', false);

    $fields = array(
        'address1',
        'address2',
        'city',
        'region',
        'country',
        'postal_code',
        'phone',
        'website',
        'favoritebook',
        'aboutme',
        'dob',
        'tos',
    );

    $tosarticle = $this->params->get('register_tos_article');
    $tosenabled = $this->params->get('register-require_tos', 0);

    // We need to be in the registration form, field needs to be enabled and we need an article ID
    if ($name != 'com_users.registration' || !$tosenabled || !$tosarticle)
    {
        // We only want the TOS in the registration form
        $form->removeField('tos', 'profiletest');
    }
    else
    {
        // Push the TOS article ID into the TOS field.
        $form->setFieldAttribute('tos', 'article', $tosarticle, 'profiletest');
    }

    foreach ($fields as $field)
    {
        // Case using the users manager in admin
        if ($name == 'com_users.user')
        {
            // Remove the field if it is disabled in registration and profile
            if ($this->params->get('register-require_' . $field, 1) == 0
                && $this->params->get('profile-require_' . $field, 1) == 0)
            {
                $form->removeField($field, 'profiletest');
            }
        }
        // Case registration
        elseif ($name == 'com_users.registration')
        {
            // Toggle whether the field is required.
            if ($this->params->get('register-require_' . $field, 1) > 0)
            {
                $form->setFieldAttribute($field, 'required', ($this->params->get('register-require_' . $field) == 2) ? 'required' : '', 'profiletest');
            }
            else
            {
                $form->removeField($field, 'profiletest');
            }
        }
        // Case profile in site or admin
        elseif ($name == 'com_users.profile' || $name == 'com_admin.profile')
        {
            // Toggle whether the field is required.
            if ($this->params->get('profile-require_' . $field, 1) > 0)
            {
                $form->setFieldAttribute($field, 'required', ($this->params->get('profile-require_' . $field) == 2) ? 'required' : '', 'profiletest');
            }
            else
            {
                $form->removeField($field, 'profiletest');
            }
        }
    }

    return true;
}

What am I doing wrong?

EDIT var_dump($data); exit(); just inside onUserAfterSave:

array(20) { ["isRoot"]=> NULL ["id"]=> int(1291) ["name"]=> string(4) "test" ["username"]=> string(4) "test" ["email"]=> string(22) "[email protected]" ["password"]=> string(65) "5757d7ea6f205f0ee9102e41f66939b4:7dTHzEolpDFKa9P2wmZ4SYSjJSedWFXe" ["password_clear"]=> string(4) "test" ["usertype"]=> NULL ["block"]=> NULL ["sendEmail"]=> int(0) ["registerDate"]=> string(19) "2013-03-05 17:00:40" ["lastvisitDate"]=> NULL ["activation"]=> NULL ["params"]=> string(2) "{}" ["groups"]=> array(1) { [0]=> string(1) "2" } ["guest"]=> int(1) ["lastResetTime"]=> NULL ["resetCount"]=> NULL ["aid"]=> int(0) ["password2"]=> string(4) "test" }
Progressist answered 22/2, 2013 at 17:14 Comment(2)
Can you clarify are you aiming to replace the profile plugin or extend it? Also add the rest of your plugins files via a link or pastebin?Nomanomad
@cppl I want to have my own plugin that does everything of the user profile plugin but is extended to add a few things I need. I will try to add a pastebin but it is identical to the user profile plugin. I only changed profile with profiletest. Once that is working then I can start adding my code.Progressist
G
1

First of all use JDump or var_dump() the array $data->profiletest to check you have data. If not then I guess you will need to go analyse the onContentPrepareForm method. If not then go and check the UserID is pulling in a valid result. One of the two must be giving a invalid result to 'fail' the if statement. Once you've done that post back here with the results :)

Guyette answered 4/3, 2013 at 13:55 Comment(18)
userId gives the valid result so it is $data->profiletest that is not set. The problem is trying to figure out why...any ideas? I posted the onContentPrepareFormProgressist
@Progressist When you've done the var_dump there it doesn't look like you've actually got any of new user fields in the data array at all. Which means at some point in the onContentPrepareForm you must not be picking up the data from the form. Do your newly created fields have the expected name structure of jform[profiletest][address1] etc. etc.?Guyette
Yes, if you look at the html source I do have the expected name structure: jform[profiletest][address1] etc.Progressist
Just noticed on the tuto you're using their is no if (!isset($data->profiletest) and $userId > 0) in the onContentPrepareData function!! It checks for the id and then goes straight into the DB queryGuyette
Yes, but that is based on 1.6. Either way I took it out and it does go further but will just fail again at if ($userId && $result && isset($data['profiletest']) && (count($data['profiletest']))) in onUserAfterSave. I can take that out but it doesn't have any data at that point so the problem has to be onContentPrepareForm or onContentPrepareDataProgressist
Thing is the Form must be being prepared because the extra fields are showingGuyette
did you remember to change the fieldset names in the profile.xml file?Guyette
If not I have created the profile plugin with the profiletest sub'd in which works and you can go through each file with a file comparer to try and work out where you've gone wrong :)Guyette
So it worked for you? Can you post the code somewhere so I can compare?Progressist
Yup - just to check - did you change the fields/fieldsets in profile.xml?Guyette
georgesjunk.co.uk/plugins/user/profiletest.zip Thats the zip of my version. Note the langauge files are missing. I just zipped up the core - but I hope you can do that on your own!Guyette
Well I tried and still no luck. What works for you? Do you see an entry in your #__user_profiles table? I had to change one thing in your zip (other than adding language files). You had <filename plugin="profile">profiletest.php</filename> in profiletest.xml. I changed that to <filename plugin="profiletest">profiletest.php</filename> otherwise it will not install (because of the collision with the Joomla core user profile plugin). Have you removed the Joomla user profile plugin to get this to work?Progressist
No haven't removed the core user profile. Nice catch about the plugin=profile bit. But I changed that and it still worked nicely for me. Yes I do see an entry in the #_user_profiles table. Only thing I might be doing different to you is installing the plugin through the discover method rather than the straight install methodGuyette
Just tried installing through the straight install method and worked fine for me. Have you tried installing my version on a blank version of Joomla? Perhaps theirs some kind of wacky conflict going on somewhereGuyette
Must be a conflict. I guess I need to reset things. Thanks for the help.Progressist
Did you try on a blank copy then? No worries for the help though!Guyette
No not yet. Too much work at this point. Thanks to you, by process of elimination it has to be environmental. So I'll have to get to this. I'm going to write this up once I get it done.Progressist
No worries :) Sorry I couldn't help you to get it working. Glad to be of help though.Guyette
K
3

So the key function here is actually the one that you are not including: onContentPrepareForm. This is the function that builds the form that the user fills out. You have not updated the field names within this, so the checks in the code that you have included fail.

If you go to the registration page with your plugin turned on, you should see all of the fields for the profile plugin. If you inspect any of the fields (let's use Address 1), it should have a name like so: jform[profile][address1]. We want this to be jform[profiletype][address1] and then your code will work.

Before getting to that though, let me explain the code a bit. The $data variable should have all the information from the form that was submitted. This matches everything that has jform at the start of the name, since that is the standard control used for the registration form by Joomla.

$data will then contain some individual items and the array profile. To update that name, find the file that was at plugins/user/profile/profiles/profile.xml and change the fields name from profile to profiletype. Now when submitted $data will contain the array element profiletype and the rest of the queries will run.

Knighten answered 4/3, 2013 at 23:24 Comment(6)
Thanks for the response. I do indeed see: jform[profiletype][address1]. My fields in profiles/profile.xml does have fields name=profiletest. Any other ideas? I've added onContentPrepareForm but again this is just a copy with changes of profile to profiletestProgressist
mistake in my comment. I'm using profiletest not profiletypeProgressist
Ok. So if you load a registration form on your site, you see the fields and they have the right name. Then you should check that the $data contains the array on save. Just inside the onUserAfterSave function add var_dump($data); exit(). Does this show an array called profiletest?Knighten
Yes there is a big array with many fields in it. But no array called profiletest. I posted the array in the question above. Just looks like the stuff from the default registration.Progressist
Definitely just the stuff from the default registration. I'm really not sure in this case. If you can see the form and filled out all the profile fields and they have the right name, the data should be in that variable. The only other piece I could guess is to check if for some reason the fields are split between two form tags. That seems very unlikely though. Are you just testing this on localhost or is there a place I could see the form?Knighten
It is on a dev site that is locked down unfortunately. The form is the same. Although the other entries look like this: jform[name] and the extra ones like address1 look like jform[profiletest][address1]. I think that is expected. Thanks for trying.Progressist
G
1

First of all use JDump or var_dump() the array $data->profiletest to check you have data. If not then I guess you will need to go analyse the onContentPrepareForm method. If not then go and check the UserID is pulling in a valid result. One of the two must be giving a invalid result to 'fail' the if statement. Once you've done that post back here with the results :)

Guyette answered 4/3, 2013 at 13:55 Comment(18)
userId gives the valid result so it is $data->profiletest that is not set. The problem is trying to figure out why...any ideas? I posted the onContentPrepareFormProgressist
@Progressist When you've done the var_dump there it doesn't look like you've actually got any of new user fields in the data array at all. Which means at some point in the onContentPrepareForm you must not be picking up the data from the form. Do your newly created fields have the expected name structure of jform[profiletest][address1] etc. etc.?Guyette
Yes, if you look at the html source I do have the expected name structure: jform[profiletest][address1] etc.Progressist
Just noticed on the tuto you're using their is no if (!isset($data->profiletest) and $userId > 0) in the onContentPrepareData function!! It checks for the id and then goes straight into the DB queryGuyette
Yes, but that is based on 1.6. Either way I took it out and it does go further but will just fail again at if ($userId && $result && isset($data['profiletest']) && (count($data['profiletest']))) in onUserAfterSave. I can take that out but it doesn't have any data at that point so the problem has to be onContentPrepareForm or onContentPrepareDataProgressist
Thing is the Form must be being prepared because the extra fields are showingGuyette
did you remember to change the fieldset names in the profile.xml file?Guyette
If not I have created the profile plugin with the profiletest sub'd in which works and you can go through each file with a file comparer to try and work out where you've gone wrong :)Guyette
So it worked for you? Can you post the code somewhere so I can compare?Progressist
Yup - just to check - did you change the fields/fieldsets in profile.xml?Guyette
georgesjunk.co.uk/plugins/user/profiletest.zip Thats the zip of my version. Note the langauge files are missing. I just zipped up the core - but I hope you can do that on your own!Guyette
Well I tried and still no luck. What works for you? Do you see an entry in your #__user_profiles table? I had to change one thing in your zip (other than adding language files). You had <filename plugin="profile">profiletest.php</filename> in profiletest.xml. I changed that to <filename plugin="profiletest">profiletest.php</filename> otherwise it will not install (because of the collision with the Joomla core user profile plugin). Have you removed the Joomla user profile plugin to get this to work?Progressist
No haven't removed the core user profile. Nice catch about the plugin=profile bit. But I changed that and it still worked nicely for me. Yes I do see an entry in the #_user_profiles table. Only thing I might be doing different to you is installing the plugin through the discover method rather than the straight install methodGuyette
Just tried installing through the straight install method and worked fine for me. Have you tried installing my version on a blank version of Joomla? Perhaps theirs some kind of wacky conflict going on somewhereGuyette
Must be a conflict. I guess I need to reset things. Thanks for the help.Progressist
Did you try on a blank copy then? No worries for the help though!Guyette
No not yet. Too much work at this point. Thanks to you, by process of elimination it has to be environmental. So I'll have to get to this. I'm going to write this up once I get it done.Progressist
No worries :) Sorry I couldn't help you to get it working. Glad to be of help though.Guyette
P
0

I think you have a problem here: 'profiletest.%' You shouldn't put the php concatenate operator inside the quote, it is treating that as part of the string. Personally, I usually concatenate the % before writing the query. But $db->quote('profiletest.'.$k).' which you have later is more along the lines of what you want.

Patmore answered 22/2, 2013 at 19:7 Comment(1)
I only changed profile with profiletest otherwise it is core Joomla code. I've changed nothing else. Either way it doesn't matter as I never get to the code that you are talking about. The if statements way above the code you mention never is true. So I don't think what you are suggesting will do anything.Progressist
D
0

Since $data['profiletest'] fails

The change of name from profile to profiletest has not been registered in xml

please make the following changes if u haven't.

In plugins\user\profile\profiles\profile.xml

change <fields name="profile"> to <fields name="profiletest">

Also in user\profile\profile.xml

change <filename plugin="profile">profile.php</filename>

to

<filename plugin="profile">profiletest.php</filename>
Dittany answered 8/3, 2013 at 13:58 Comment(1)
Yes I did, although tutorials always seem to show this file: user\profile\profile.xml should be user\profile\profiletest.xml and this will have: <filename plugin="profiletest">profiletest.php</filename>. I did try but still no luck.Progressist

© 2022 - 2024 — McMap. All rights reserved.