Seditio Source
Root |
./othercms/ips_4.3.4/applications/core/extensions/core/ProfileSteps/ProfileFields.php
<?php
/**
 * @brief        Profile Completion Extension
 * @author        <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
 * @copyright    (c) Invision Power Services, Inc.
 * @license        https://www.invisioncommunity.com/legal/standards/
 * @package        Invision Community
 * @since        16 Nov 2016
 */

namespace IPS\core\extensions\core\ProfileSteps;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
   
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
    exit;
}

/**
 * Profile fields extension
 */
class _ProfileFields
{
   
/**
     * Available parent actions to complete steps
     *
     * @return    array    array( 'key' => 'lang_string' )
     */
   
public static function actions()
    {
       
$return = array();
       
        if ( \
IPS\core\ProfileFields\Field::fieldData() )
        {
           
$return['profile_fields'] = 'complete_profile_app__core_ProfileFields';
        }
       
        return
$return;
    }
   
   
/**
     * Available sub actions to complete steps
     *
     * @return    array    array( 'key' => 'lang_string' )
     */
   
public static function subActions()
    {
       
$return = array();
       
        foreach( \
IPS\core\ProfileFields\Field::fieldData() AS $fieldData )
        {
            foreach(
$fieldData AS $id => $field )
            {
               
$field = \IPS\core\ProfileFields\Field::constructFromData( $field );
                if ( !
$field->admin_only )
                {
                   
$return['profile_fields'][ 'core_pfield_' . $field->_id ] = 'core_pfield_' . $field->_id;
                }
            }
        }
       
        return
$return;
    }
   
   
/**
     * Can the actions have multiple choices?
     *
     * @param    string        $action        Action key (basic_profile, etc)
     * @return    boolean
     */
   
public static function actionMultipleChoice( $action )
    {
        return
TRUE;
    }

   
/**
     * Can be set as required?
     *
     * @return    array
     * @note    This is intended for items which have their own independent settings and dedicated enable pages, such as MFA and Social Login integration
     */
   
public static function canBeRequired()
    {
        return array(
'profile_fields' );
    }
   
   
/**
     * Has a specific step been completed?
     *
     * @param    \IPS\Member\ProfileStep    The step to check
     * @param    \IPS\Member|NULL        The member to check, or NULL for currently logged in
     * @return    bool
     */
   
public function completed( \IPS\Member\ProfileStep $step, \IPS\Member $member = NULL )
    {
       
$member = $member ?: \IPS\Member::loggedIn();
       
        if ( !
$member->group['g_edit_profile'] )
        {
           
/* Member has no permission to edit profile */
           
return TRUE;
        }
       
       
/* Does the member have any profile fields? */
       
if ( ! count( $member->profileFields() ) )
        {
            return
FALSE;
        }
       
       
$done = 0;
        foreach(
$step->subcompletion_act as $item )
        {
           
$fieldId = \substr( $item, 12 );
           
            foreach(
$member->profileFields() AS $group => $field )
            {
                foreach(
$field AS $key => $value )
                {
                    if (
$key == 'core_pfield_' . $fieldId )
                    {
                        if ( (bool)
$value )
                        {
                           
$done++;
                        }
                    }
                }
            }
        }
       
        return (
$done === count( $step->subcompletion_act ) );
    }
   
   
/**
     * Action URL
     *
     * @param    string                The action
     * @param    \IPS\Member|NULL    The member, or NULL for currently logged in
     * @return    \IPS\Http\Url
     */
   
public function url( $action, \IPS\Member $member = NULL )
    {
        return \
IPS\Http\Url::internal( "app=core&module=members&controller=profile&do=edit&id={$member->member_id}", 'front', 'edit_profile', $member->members_seo_name );
    }
   
   
/**
     * Post ACP Save
     *
     * @param    \IPS\Member\ProfileStep        The step
     * @param    array                        Form Values
     * @return    void
     */
   
public function postAcpSave( \IPS\Member\ProfileStep $step, array $values )
    {
       
$subActions = static::subActions()['profile_fields'];
       
       
/* If we are going to add a profile field to a step, or even require it, we need to make sure the actual field is updated */
       
foreach( $subActions AS $key )
        {
            if (
in_array( $key, $values['step_subcompletion_act'] ) )
            {
               
$fieldId = \substr( $key, 12 );
               
$update = array();
               
$update['pf_show_on_reg'] = 1;
               
$update['pf_not_null'] = $step->required;
               
                \
IPS\Db::i()->update( 'core_pfields_data', $update, array( "pf_id=?", $fieldId ) );
            }
        }
       
        unset( \
IPS\Data\Store::i()->profileFields );
    }
   
   
/**
     * Format Form Values
     *
     * @param    array
     * @param    \IPS\Member
     * @param    \IPS\Helpers\Form
     * @return    void
     */
   
public static function formatFormValues( $values, &$member, &$form )
    {
       
$member = $member ?: \IPS\Member::loggedIn();
       
       
$profileFields = array();
        foreach ( \
IPS\core\ProfileFields\Field::roots() as $field )
        {
            if ( isset(
$values[ "core_pfield_{$field->_id}"] ) )
            {
                if(
$field->required and ( $values[ "core_pfield_{$field->_id}" ] === NULL or !isset( $values[ "core_pfield_{$field->_id}" ] ) ) )
                {
                    \
IPS\Output::i()->error( 'reg_required_fields', '1C223/5', 403, '' );
                }
               
               
$helper = $field->buildHelper();
               
$profileFields[ "field_{$field->_id}" ] = $helper::stringValue( $values[ "core_pfield_{$field->_id}" ] );
               
                if (
$helper instanceof \IPS\Helpers\Form\Editor )
                {
                   
$field->claimAttachments( $member->member_id );
                }
            }
        }
       
        if (
count( $profileFields ) )
        {
           
/* Use insert into ... on duplicate key update here to cover both cases where the row exists or does not exist */
           
\IPS\Db::i()->insert( 'core_pfields_content', array_merge( array( 'member_id' => $member->member_id ), $profileFields ), true );

           
/* Track and sync the changed custom fields */
           
$member->changedCustomFields = $profileFields;
           
$member->save();
        }
    }
   
   
/**
     * Wizard Steps
     *
     * @param    \IPS\Member    $member    Member or NULL for currently logged in member
     * @return    array
     */
   
public static function wizard( \IPS\Member $member = NULL )
    {
       
$member = $member ?: \IPS\Member::loggedIn();
       
$wizards = array();
       
        foreach( \
IPS\Member\ProfileStep::loadAll() AS $step )
        {
            try
            {
               
$values = \IPS\Db::i()->select( '*', 'core_pfields_content', array( 'member_id = ?', $member->member_id ) )->first();

                foreach(
$values as $k => $v )
                {
                    if(
$k == 'member_id' )
                    {
                        continue;
                    }

                   
$profileFields[ 'core_p' . $k ] = $v;
                }
            }
            catch( \
UnderflowException $e )
            {
               
$profileFields = array();
            }

            if (
$step->completion_act === 'profile_fields' AND ! $step->completed( $member ) )
            {
               
$wizards[ $step->key ] = function( $data ) use ( $member, $step, $profileFields ) {
                   
$form = new \IPS\Helpers\Form( 'profile_profile_fields_' . $step->id, 'profile_complete_next' );
                   
                    foreach(
$step->subcompletion_act as $item )
                    {
                       
$id        = \substr( $item, 12 );
                       
$field    = \IPS\core\ProfileFields\Field::load( $id );
                       
                        if ( !
$field->admin_only )
                        {
                           
$value = isset( $profileFields['core_pfield_' . $id] ) ? $profileFields['core_pfield_' . $id] : NULL;

                            if (
is_array( $value ) and $field->multiple )
                            {
                               
$value = implode( ',', array_keys( explode( '<br>', $value ) ) );
                            }
                           
                            if (
$field->type === 'Editor' )
                            {
                               
$field::$editorOptions['autoSaveKey'] = md5( get_class( $field ) . '-' . $field->_id . '-' . $member->member_id );
                               
$field::$editorOptions['attachIds'] = array( $member->member_id, $field->_id );
                            }
                           
                           
$form->add( $field->buildHelper( $value ) );
                        }
                    }
                   
                    if (
$values = $form->values() )
                    {
                        static::
formatFormValues( $values, $member, $form );
                       
$member->save();
                       
                        return
$values;
                    }

                    return
$form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'profileCompleteTemplate' ), $step );
                };
            }
        }
       
        if (
count( $wizards ) )
        {
            return
$wizards;
        }
    }

   
/**
     * Post Delete
     * @param    \IPS\Member\ProfileStep        The step
     *
     * @return    void
     */
   
public function onDelete( \IPS\Member\ProfileStep $step )
    {
       
$subActions = static::subActions()['profile_fields'];

       
$notChangeableFields = array(
           
'CheckboxSet',
           
'Radio'
       
);

       
/* If we are going to add a profile field to a step, or even require it, we need to make sure the actual field is updated */
       
foreach( $subActions AS $key )
        {
            if (
in_array( $key, $step->subcompletion_act ) )
            {
               
$fieldId = \substr( $key, 12 );
               
$update = array();
               
                try
                {
                   
$field     = \IPS\core\ProfileFields\Field::load( $fieldId );
   
                    if (
in_array( $field->type, $notChangeableFields ) )
                    {
                       
/* reset the pf_not_null field to 0 if this field can't be set via the fields form */
                       
if ( $step->required )
                        {
                           
$update['pf_not_null'] = 0;
                            \
IPS\Db::i()->update( 'core_pfields_data', $update, array( "pf_id=?", $fieldId ) );
                        }
                    }
                }
                catch( \
OutOfRangeException $e ) { }
            }
        }

        unset( \
IPS\Data\Store::i()->profileFields );
    }
   
   
/**
     * Resyncs when something external happens
     * @param    \IPS\Member\ProfileStep        The step
     *
     * @return void
     */
   
public function resync( \IPS\Member\ProfileStep $step )
    {
       
$subActions = array();
       
        foreach(
$step->subcompletion_act as $item )
        {
           
$fieldId = \substr( $item, 12 );
            try
            {
                \
IPS\core\ProfileFields\Field::load( $fieldId );
               
$subActions[] = $item;
            }
            catch( \
OutOfRangeException $e )
            {
               
/* No longer exists.. */
           
}
        }
       
        if (
count( $subActions ) and count( $subActions ) != $step->subcompletion_act )
        {
           
$step->subcompletion_act = $subActions;
           
$step->save();
        }
        else if ( !
count( $subActions ) )
        {
           
/* No fields left, so delete this */
           
$step->delete();
        }
     }
}