Alter save in ACP

Lukas W.

Well-known member
I've altered the xen_user_field table in the database and extended it by a new column.




Also I altered the matching piece inside the ACP to support the new field.



But as by now, the selected value inside the ACP is not altered in the table. Guess I have to edit some php file here? If so, which one and how is it normally done without altering existing xenforo files?
 
Guess I have to replace the DataWriter of UserField.php, as it is probably not recommended to alter the file when creating a public mod. Would have coppied and altered the file, then altered the save-call inside the template. I am however struggling to understand the call inside the template for the DataWriter or better said, how to replace the DataWriter called here.

Code:
<xen:form action="{xen:adminlink 'user-fields/save', $field}" class="AutoValidator" data-redirect="on">

Is it simply enough to provide a new one with the same file name inside my addon? Probably not i guess...
 
You will want to use the class proxy system. That call is a submission to a URL that is run by a controller.
 
I've tried to follow this Tutorial, but it seems 'unnecessary' much stuff for a single line of code. I am somewhere between creating two files and having no idea what to do next or which Event Listener to extend (probably load_class_datawriter...) but as said, is it correct that I need to set up two files for one additional line? I am effectively adding
Code:
'permissionSecure'        => array('type'    => self::TYPE_BOOLEAN, 'default' => 0)
to
Code:
protected function _getFields()
    {
        return array(
            'xf_user_field' => array(
                'field_id'              => array('type' => self::TYPE_STRING, 'required' => true, 'maxLength' => 25,
                        'verification' => array('$this', '_verifyFieldId'), 'requiredError' => 'please_enter_valid_field_id'
                ),
                'display_group'         => array('type' => self::TYPE_STRING, 'default' => 'personal',
                    'allowedValues' => array('personal', 'contact', 'preferences')
                ),
                'display_order'         => array('type' => self::TYPE_UINT, 'default' => 1),
                'field_type'            => array('type' => self::TYPE_STRING, 'default' => 'textbox',
                    'allowedValues' => array('textbox', 'textarea', 'select', 'radio', 'checkbox', 'multiselect')
                ),
                'field_choices'         => array('type' => self::TYPE_SERIALIZED, 'default' => ''),
                'match_type'            => array('type' => self::TYPE_STRING, 'default' => 'none',
                    'allowedValues' => array('none', 'number', 'alphanumeric', 'email', 'url', 'regex', 'callback')
                ),
                'match_regex'           => array('type' => self::TYPE_STRING, 'default' => '', 'maxLength' => 250),
                'match_callback_class'  => array('type' => self::TYPE_STRING, 'default' => '', 'maxLength' => 75),
                'match_callback_method' => array('type' => self::TYPE_STRING, 'default' => '', 'maxLength' => 75),
                'max_length'            => array('type' => self::TYPE_UINT, 'default' => 0),
                'required'              => array('type' => self::TYPE_BOOLEAN, 'default' => 0),
                'show_registration'     => array('type' => self::TYPE_BOOLEAN, 'default' => 0),
                'user_editable'         => array('type' => self::TYPE_STRING, 'default' => 'yes',
                    'allowedValues' => array('yes', 'once', 'never')
                ),
                'viewable_profile'      => array('type' => self::TYPE_BOOLEAN, 'default' => 1),
                'viewable_message'      => array('type' => self::TYPE_BOOLEAN, 'default' => 0),
                'display_template'      => array('type' => self::TYPE_STRING, 'default' => ''),
           
                //Permission Secure Extension
                'permissionSecure'        => array('type'    => self::TYPE_BOOLEAN, 'default' => 0)
            )
        );
    }


Edit: I think I have done a step in the right direction. I have now created my class as "Katsulynx/KLCPFP/DataWriter/UserField.php"
PHP:
<?php
class Katsulynx_KLCPFP_DataWriter_UserField extends XFCP_Katsulynx_KLCPFP_DataWriter_UserField
{
  protected function _getFields()
    {
        return array(
            'xf_user_field' => array(
                'field_id'              => array('type' => self::TYPE_STRING, 'required' => true, 'maxLength' => 25,
                        'verification' => array('$this', '_verifyFieldId'), 'requiredError' => 'please_enter_valid_field_id'
                ),
                'display_group'         => array('type' => self::TYPE_STRING, 'default' => 'personal',
                    'allowedValues' => array('personal', 'contact', 'preferences')
                ),
                'display_order'         => array('type' => self::TYPE_UINT, 'default' => 1),
                'field_type'            => array('type' => self::TYPE_STRING, 'default' => 'textbox',
                    'allowedValues' => array('textbox', 'textarea', 'select', 'radio', 'checkbox', 'multiselect')
                ),
                'field_choices'         => array('type' => self::TYPE_SERIALIZED, 'default' => ''),
                'match_type'            => array('type' => self::TYPE_STRING, 'default' => 'none',
                    'allowedValues' => array('none', 'number', 'alphanumeric', 'email', 'url', 'regex', 'callback')
                ),
                'match_regex'           => array('type' => self::TYPE_STRING, 'default' => '', 'maxLength' => 250),
                'match_callback_class'  => array('type' => self::TYPE_STRING, 'default' => '', 'maxLength' => 75),
                'match_callback_method' => array('type' => self::TYPE_STRING, 'default' => '', 'maxLength' => 75),
                'max_length'            => array('type' => self::TYPE_UINT, 'default' => 0),
                'required'              => array('type' => self::TYPE_BOOLEAN, 'default' => 0),
                'show_registration'     => array('type' => self::TYPE_BOOLEAN, 'default' => 0),
                'user_editable'         => array('type' => self::TYPE_STRING, 'default' => 'yes',
                    'allowedValues' => array('yes', 'once', 'never')
                ),
                'viewable_profile'      => array('type' => self::TYPE_BOOLEAN, 'default' => 1),
                'viewable_message'      => array('type' => self::TYPE_BOOLEAN, 'default' => 0),
                'display_template'      => array('type' => self::TYPE_STRING, 'default' => ''),
              
                //Permission Secure Extension
                'permissionSecure'        => array('type'    => self::TYPE_BOOLEAN, 'default' => 0)
            )
        );
    }
}
?>
and the corresponding Listener "Katsulynx/KLCPFP/Listener/DataWriter.php"
PHP:
<?php

class Katsulynx_KLCPFP_Listener_DataWriter
{
    /**
     * Instruct the system that XenForo_ControllerPublic_Member
     * should be extended by Dev_ControllerPublic_Member
     *
     * @param string $class
     * @param array $extend
     */
    public static function extendUserDataWriter($class, array &$extend)
    {
        if ($class == 'XenForo_DataWriter_UserField')
        {
            $extend[] = 'Katsulynx_KLCPFP_DataWriter_UserField';
        }
    }
}

and set up the Code Event Listener
01.webp

Is this, how it should be done?

Edit2: Seems not to work however, don't know if it is the extension setup or I haven't done the right extensions yet.
 
Last edited:
You are on the right track. Except you don't want to full sail replace the function. You want to return the array from the parents class (generated by it) with yours inserted.

You are now only half of the way there. You need to extend the controller as well to insert the proper data.
 
So I want to merge my single line array with the array given back by the Parent class when calling
PHP:
parent::_getFields()
inside my class and return that one?

Like this?
PHP:
<?php
class Katsulynx_KLCPFP_DataWriter_UserField extends XFCP_Katsulynx_KLCPFP_DataWriter_UserField
{
  protected function _getFields()
    {
    
        return array_merge ( parent::_getFields(), array('xf_user_field' => array('permissionSecure'=> array('type' => self::TYPE_BOOLEAN, 'default' => 0))));

    }
}
?>

Edit: Haha, at least I can see something happening now, when altering the options, I'll get an error message thrown when trying to save :ROFLMAO:
Code:
lease correct the following errors:

The requested field could not be found.
The field 'display_group' was not recognised.
Display Order:
The field 'display_order' was not recognised.
The field 'field_type' was not recognised.
The field 'match_type' was not recognised.
The field 'match_regex' was not recognised.
The field 'match_callback_class' was not recognised.
The field 'match_callback_method' was not recognised.
Maximum Length:
The field 'max_length' was not recognised.
The field 'required' was not recognised.
The field 'show_registration' was not recognised.
The field 'viewable_profile' was not recognised.
The field 'viewable_message' was not recognised.
Value Display HTML:
The field 'display_template' was not recognised.
The field 'user_editable' was not recognised.
The field 'field_choices' was not recognised.

Edit2: Guess this is a better approach:
PHP:
<?php
class Katsulynx_KLCPFP_DataWriter_UserField extends XFCP_Katsulynx_KLCPFP_DataWriter_UserField
{
  protected function _getFields()
    {
       
        $parrent_array = parent::_getFields();
        $array_extension = array('permissionSecure'=> array('type' => self::TYPE_BOOLEAN, 'default' => 0));
       
        $parrent_array['xf_user_field'] = array_merge($parrent_array['xf_user_field'], $array_extension);
       
        return $parrent_array;
    }
}
?>
The error message seems to be gone, but however it still denies to save my new settings, seems like I am still missing something...
 
Last edited:
Yes, now that you have the data writer, you need to modify the actual save. Have you ever used the DataWriters?
 
I've taken a deeper look into it, but I'm somehow not clever enough to get on the right track. As I am missing the save, I'll probably have to alter either the _postSave() or _preSave() method, but they both seem pretty much completed as they are... The only other thing I could image is, that my new field is not processed in the setFieldChoices(), but I can't determine, where this method gets its arguments from. <- Stupid me, is set in the _preSave(). So I'd say I am definitly lacking something in the setFieldChoices or, more likely, in the preSave.
 
Last edited:
Started to edit the _preSave()-function to fit my needs. But I haven't yet found out how to receive the selected value (if the field is checked or unchecked) yet. I am however able to save a predefined value by now :LOL: My new function looks like this:

PHP:
protected function _preSave() {
        parent::_preSave();  
      
        //TODO: Select value and replace that zero with the respective variable
        $this->set('permissionSecure', 0);
    }

Could someone give me a hint on how to get the needed value? I've experimented with the getter-method, but realized that this is kind of stupid, as it (at least I think so), receives the currently set value from the database. When I did so, I achieved that the field was automatically unset if it was set in the database and the other way round when saving :ROFLMAO:.
 
Top Bottom