创建 Joomla 用户资料插件

7
我已经为我的Joomla 2.5.9安装直接克隆了用户资料插件。
我已经按照旧的1.6版本中的tutorial,将插件和文件重命名为'profiletest'。
我在表单中添加了一个新的输入项,在后端一切正常,并且新条目如预期地显示在前端的注册表单中。但是,当您注册时,我从未看到#__user_profiles表被更新。
这里有很多代码,但它是用户资料插件(/plugins/user/profile/)的副本。这是profiletest.php onUserAfterSave函数:
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;
}

它从未向数据库中插入任何内容,因为它从未进入此if语句:
if ($userId && $result && isset($data['profiletest']) && (count($data['profiletest'])))

基本上这个条件失败了:$data['profiletest'] 看起来很基础,因为我在插件中只更改了'profile'为'profiletest'。然而,为了解决这个问题,我认为您需要查看我的另一个名为onContentPrepareData的函数。虽然它没有做任何不同的事情,只是名称更改。抱歉内容有点长。
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;
}

再次注意到我从未进入这里:

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

这可能会影响到onUserAfterSave函数。 编辑 这里是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;
}

我做错了什么?
onUserAfterSave函数内部,编辑var_dump($data); exit();
array(20) { ["isRoot"]=> NULL ["id"]=> int(1291) ["name"]=> string(4) "test" ["username"]=> string(4) "test" ["email"]=> string(22) "test@test.com" ["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" }

你能澄清一下,你是想要替换个人资料插件还是扩展它?同时,通过链接或pastebin添加你的其他插件文件。 - Craig
@cppl 我想要拥有自己的插件,它可以完成用户资料插件的所有功能,并且可以扩展添加我需要的一些功能。我将尝试添加一个pastebin,但它与用户资料插件完全相同。我只是将“profile”更改为“profiletest”。一旦这个工作正常,我就可以开始添加我的代码了。 - Tom
4个回答

3
所以这里的关键函数实际上是您未包含的函数:onContentPrepareForm。 这个函数构建了用户填写的表单。 您没有更新此中的字段名称,因此在您包含的代码中检查失败。
如果您打开插件并前往注册页面,应该会看到所有与配置文件插件有关的字段。 如果您检查任何字段(假设我们使用地址1),那么它应该像这样具有名称:jform [profile] [address1]。 我们希望它变成jform [profiletype] [address1],然后您的代码就可以正常工作了。
在此之前,让我解释一下代码。 $data 变量应该包含从提交的表单中获取的所有信息。 这与Joomla注册表单使用的标准控件的名称相匹配,因为名称以 jform 开头。
然后, $data 将包含一些单独的项目和数组 profile 。 要更新该名称,请找到位于 plugins / user / profile / profiles / profile.xml 的文件,并将 fields 名称从 profile 更改为 profiletype 。 现在提交时, $data 将包含数组元素 profiletype 和其余查询将运行。

感谢您的回复。我确实看到了:jform [profiletype] [address1]。我的profiles/profile.xml中的字段确实有 fields name = profiletest。还有其他的想法吗?我已经添加了onContentPrepareForm,但这只是将profile复制为profiletest并进行更改。 - Tom
我的评论中有错误。我使用的是profiletest而不是profiletype - Tom
好的。所以,如果您在站点上加载一个注册表单,您将看到这些字段,并且它们具有正确的名称。然后您应该检查$data是否包含保存的数组。在onUserAfterSave函数内添加var_dump($data); exit()。这会显示名为profiletest的数组吗? - David Fritsch
是的,有一个包含许多字段的大数组。但是没有名为profiletest的数组。我在上面的问题中发布了该数组。它看起来就像默认注册表单中的内容。 - Tom
肯定只是默认注册表单的内容。在这种情况下,我真的不确定。如果您可以看到表单并填写了所有个人资料字段,并且它们的名称正确,则数据应该在该变量中。我唯一能猜测的另一个部分是检查是否由于某种原因字段被分成两个表单标签。虽然这似乎非常不可能。您只是在本地主机上测试还是有其他地方可以看到表单? - David Fritsch
很不幸,它在一个被锁定的开发网站上。表单是一样的。虽然其他条目看起来像这样:jform[name],而额外的条目,如address1,则看起来像jform[profiletest][address1]。我认为这是可以预料的。感谢您的尝试。 - Tom

1
首先,使用 JDump 或 var_dump() 函数来检查数组 $data->profiletest 是否有数据。如果没有数据,则需要分析 onContentPrepareForm 方法。如果有数据,则需要检查 UserID 是否返回有效结果。其中之一必须使 if 语句失效。完成后,请在此处发布结果 :)

userId 返回有效结果,因此问题在于 $data->profiletest 没有设置。现在的问题是如何找出原因……你有什么想法吗?我已经发布了 onContentPrepareForm - Tom
@Tom 当你执行了 var_dump 后,看起来数据数组中根本没有新用户字段。这意味着在 onContentPrepareForm 的某个时候,你必须没有从表单中获取数据。你新创建的字段是否具有预期的名称结构,如 jform[profiletest][address1] 等等? - George Wilson
如果没有,我已经创建了带有profiletest子程序的配置文件插件,它可以工作,您可以使用文件比较器逐个查看每个文件,以尝试找出您出了什么问题 :) - George Wilson
我尝试了但仍然没有成功。你有什么方法可以解决吗?在你的 #__user_profiles 表中是否看到了一个条目?除了添加语言文件之外,我还需要更改你的 zip 中的一件事情。在 profiletest.xml 中,你使用了 <filename plugin="profile">profiletest.php</filename>。我将其更改为 <filename plugin="profiletest">profiletest.php</filename>,否则它将无法安装(因为与 Joomla 核心用户配置文件插件发生冲突)。你是否已删除 Joomla 用户配置文件插件以使其正常工作? - Tom
还没有。目前工作太多了。感谢您,通过排除法,问题必须是环境相关的。所以我得去解决这个问题。等我完成后,我会把它写出来。 - Tom
显示剩余13条评论

0
我认为您在这里有一个问题:'profiletest.%'。您不应该将php连接运算符放在引号内,因为它会将其视为字符串的一部分。个人而言,我通常在编写查询之前连接百分号。但是,$db->quote('profiletest.' $k). ',后面您使用的更接近于您想要的内容。

我只是将 profile 更改为 profiletest,否则它是 Joomla 的核心代码。我没有改变其他任何东西。无论如何,这都不重要,因为我从来没有进入您所说的那段代码。上面的 if 语句永远不会成立。所以我认为你所提出的建议不会起任何作用。 - Tom

0

由于 $data['profiletest'] 失败

从 profile 更改为 profiletest 的名称尚未在 xml 中注册

如果您还没有,请进行以下更改。

在 plugins\user\profile\profiles\profile.xml 中

<fields name="profile"> 更改为 <fields name="profiletest">

还要在 user\profile\profile.xml 中

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

更改为

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

是的,我试过了,尽管教程总是显示这个文件:user\profile\profile.xml 应该是 user\profile\profiletest.xml,并且它将包含:<filename plugin="profiletest">profiletest.php</filename>。我确实尝试过,但仍然没有成功。 - Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接