Files
2025-12-19 17:53:48 -08:00

284 lines
8.8 KiB
PHP

<?php
/**
* @brief Custom Package Field Node
* @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
* @subpackage Nexus
* @since 1 May 2013
*/
namespace IPS\nexus\Package;
/* To prevent PHP errors (extending class does not exist) revealing path */
use IPS\Content;
use IPS\CustomField as SystemCustomField;
use IPS\Helpers\Form;
use IPS\Helpers\Form\FormAbstract;
use IPS\Helpers\Form\Ftp;
use IPS\Helpers\Form\Node;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\YesNo;
use IPS\nexus\Package;
use IPS\Text\Encrypt;
use IPS\Theme;
use OutOfRangeException;
use function defined;
use function in_array;
use function is_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Custom Profile Field Node
*/
class CustomField extends SystemCustomField
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static array $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static ?string $databaseTable = 'nexus_package_fields';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static string $databasePrefix = 'cf_';
/**
* @brief [Node] Order Database Column
*/
public static ?string $databaseColumnOrder = 'position';
/**
* @brief [CustomField] Title/Description lang prefix
*/
protected static string $langKey = 'nexus_pfield';
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @endcode
*/
protected static ?array $restrictions = array(
'app' => 'nexus',
'module' => 'store',
'prefix' => 'package_fields_',
);
/**
* @brief [Node] Node Title
*/
public static string $nodeTitle = 'custom_package_fields';
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static ?string $titleLangPrefix = 'nexus_pfield_';
/**
* @brief [CustomField] Column Map
*/
public static array $databaseColumnMap = array(
'content' => 'extra',
'not_null' => 'required'
);
/**
* @brief [CustomField] Additional Field Classes
*/
public static array $additionalFieldTypes = array(
'UserPass' => 'sf_type_UserPass',
'Ftp' => 'sf_type_Ftp'
);
/**
* @brief [CustomField] Upload Field Storage Extension
*/
public static string $uploadStorageExtension = 'nexus_PurchaseFields';
/**
* @brief [CustomField] Editor Options
*/
public static array $editorOptions = array( 'app' => 'nexus', 'key' => 'Purchases' );
/**
* @brief [CustomField] Additional Field Toggles
*/
public static array $additionalFieldToggles = array(
'Address' => array( 'cf_sticky' ),
'Checkbox' => array( 'cf_sticky' ),
'CheckboxSet' => array( 'cf_sticky' ),
'Date' => array( 'cf_sticky' ),
'Email' => array( 'cf_sticky' ),
'Number' => array( 'cf_sticky' ),
'Password' => array( 'cf_sticky' ),
'Radio' => array( 'cf_sticky' ),
'Text' => array( 'cf_sticky' ),
'Url' => array( 'cf_sticky' ),
);
/**
* [Node] Add/Edit Form
*
* @param Form $form The form
* @return void
*/
public function form( Form &$form ) : void
{
parent::form( $form );
$packages = array();
if( $this->packages )
{
foreach ( array_filter( explode( ',', $this->packages ) ) as $id )
{
try
{
$packages[] = Package::load( $id );
}
catch ( OutOfRangeException ) { }
}
}
$form->add( new Node( 'cf_packages', $packages, FALSE, array( 'class' => 'IPS\nexus\Package\Group', 'noParentNodes' => 'custom_packages', 'multiple' => TRUE, 'permissionCheck' => function( $node )
{
return !( $node instanceof Group);
} ) ), 'pf_desc' );
$form->add( new YesNo( 'cf_sticky', $this->sticky ?: FALSE, FALSE, array(), NULL, NULL, NULL, 'cf_sticky' ), 'pf_type' );
$form->add( new YesNo( 'cf_allow_attachments', $this->id ? $this->allow_attachments : 1, FALSE, array( ), NULL, NULL, NULL, 'pf_allow_attachments' ) );
$form->addHeader( 'display_settings' );
$form->add( new YesNo( 'cf_purchase', $this->purchase, FALSE ) );
$form->add( new YesNo( 'cf_editable', $this->editable, FALSE ) );
$form->add( new YesNo( 'cf_required', $this->required ?: FALSE, FALSE, array(), NULL, NULL, NULL, 'pf_not_null' ) );
$form->add( new YesNo( 'cf_invoice', $this->invoice ) );
unset( $form->elements[''][1] );
unset( $form->elements['']['pf_not_null'] );
unset( $form->elements['']['pf_max_input'] );
unset( $form->elements['']['pf_input_format'] );
unset( $form->elements[''][2] );
unset( $form->elements['']['pf_search_type'] );
unset( $form->elements['']['pf_search_type_on_off'] );
unset( $form->elements['']['pf_format'] );
unset( $form->elements['']['pf_allow_attachments'] );
}
/**
* [Node] Format form values from add/edit form for save
*
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( array $values ): array
{
if( isset( $values['cf_packages'] ) AND is_array( $values['cf_packages'] ) )
{
$values['packages'] = implode( ',', array_map( function( $node ){ return $node->id; }, $values['cf_packages'] ) );
unset( $values['cf_packages'] );
}
/*
* Make sure that the multiple field is set to 0 for the Radio field, otherwise the package package_stock_adjustments will fail..
* it seems that people changed a select field often to a radio field, which caused that the field was missing in the stock adjustment
*/
if( isset( $values['pf_type'] ) and $values['pf_type'] == 'Radio' )
{
$values['pf_multiple'] = 0;
}
/* Disable 'sticky' for fields that don't support it */
if( !in_array( 'cf_sticky', static::$additionalFieldToggles[ $values['pf_type'] ] ?? [] ) )
{
$values['cf_sticky'] = false;
}
return parent::formatFormValues( $values );
}
/**
* Build Form Helper
*
* @param mixed|null $value The value
* @param callback|null $customValidationCode Custom validation code
* @param Content|NULL $content The associated content, if editing
* @param int $flags
* @return Text|FormAbstract
*/
public function buildHelper( mixed $value=NULL, callable $customValidationCode=NULL, ?Content $content = NULL, int $flags=0 ): Text|FormAbstract
{
if ( $this->type === 'UserPass' )
{
$class = 'IPS\nexus\Form\\' . $this->type;
return new $class( static::$langKey . '_' . $this->id, $value, $this->not_null, array(), NULL, NULL, NULL, static::$langKey . '_' . $this->id );
}
elseif ( $this->type === 'Ftp' )
{
return new Ftp( static::$langKey . '_' . $this->id, $value, $this->not_null, array( 'validate' => $this->validate ), NULL, NULL, NULL, static::$langKey . '_' . $this->id );
}
return parent::buildHelper( $value, $customValidationCode, $content );
}
/**
* Display Value
*
* @param mixed $value The value
* @param bool $showSensitiveInformation If TRUE, potentially sensitive data (like passwords) will be displayed - otherwise will be blanked out
* @param string|null $separator Used to separate items when displaying a field with multiple values.
* @return string|null
*/
public function displayValue( mixed $value=NULL, bool $showSensitiveInformation=FALSE, ?string $separator=NULL ): ?string
{
if ( $this->type === 'UserPass' )
{
if ( !is_array( $value ) )
{
$value = json_decode( Encrypt::fromTag( $value )->decrypt(), TRUE );
}
if ( !$showSensitiveInformation )
{
$value['pw'] = '********';
}
return Theme::i()->getTemplate( 'forms', 'nexus', 'global' )->usernamePasswordDisplay( $value );
}
/* Select boxes store the value and not the index, but the parent method uses the index to determine the value.
When using numeric options, this causes the wrong value to be returned. */
if ( $this->type == 'Select' )
{
if ( $this->multiple )
{
return implode( ( $separator ) ?: '<br>', explode( ',', htmlspecialchars( $value, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', false ) ) );
}
return htmlspecialchars( $value, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', false );
}
return parent::displayValue( $value, $showSensitiveInformation );
}
}