Coding standards
Security in ResourceSpace
Developer reference
Database
Action functions
Admin functions
Ajax functions
Annotation functions
API functions
Collections functions
Comment functions
Config functions
CSV export functions
Dash functions
Debug functions
Encryption functions
Facial recognition functions
File functions
General functions
Language functions
Log functions
Login functions
Message functions
Migration functions
Node functions
PDF functions
Plugin functions
Render functions
Reporting functions
Request functions
Research functions
Slideshow functions
Theme permission functions
User functions
Video functions
Database functions
Metadata functions
Resource functions
Search functions
Map functions
Job functions
Tab functions
Test functions

update_field()

Description

Updates resource field. Works out the previous value, so this is
not efficient if we already know what this previous value is (hence
it is not used for edit where multiple fields are saved)

Parameters

ColumnTypeDefaultDescription
$resource integer Resource ID
$field integer Field ID
$value string The new value
&$errors array array Any errors that may occur during update
$log boolean true Log this change in the resource log?
$nodevalues boolean false Set to TRUE to process the value as a comma separated list of node IDs

Return

boolean

Location

include/resource_functions.php lines 2626 to 3054

Definition

 
function update_field($resource$field$value, array &$errors = array(), $log=true$nodevalues=false)
    {
    global 
$category_tree_add_parents$userref$FIXED_LIST_FIELD_TYPES$lang;

    
$resource_data get_resource_data($resource);
    if (
$resource_data === false)
        {
        
$errors[] = $lang["resourcenotfound"] . " " . (string) $resource;
        return 
false;
        }
    if (
$resource_data["lock_user"] > && $resource_data["lock_user"] != $userref)
        {
        
$errors[] = get_resource_lock_message($resource_data["lock_user"]);
        return 
false;
        }

    
// accept shortnames in addition to field refs
    
if(!is_int_loose($field))
        {
        
$field ps_value("SELECT ref AS `value` FROM resource_type_field WHERE name = ?", ["s",$field], ''"schema");
        }

    
// Fetch some information about the field
    
$fieldinfo get_resource_type_field($field);

    if(!
$fieldinfo)
        {
        
$errors[] = "No field information about field ID '{$field}'";
        return 
false;
        }

    if (
$fieldinfo["global"]==&& !in_array($resource_data['resource_type'],ps_array("SELECT resource_type value FROM resource_type_field_resource_type WHERE resource_type_field=?",array("i",$field))))
        {
        
$errors[] = "Field is not valid for this resource type";
        return 
false;
        }

    
$value $data_joins_field_value trim((string)$value);
    if(
$value === '' && $fieldinfo['required'])
        {
        
$errors[] = i18n_get_translated($fieldinfo['title']) . ": {$lang['requiredfield']}";
        return 
false;
        }
    
    
// Create arrays that will be passed to hook function later
    
$newnodes        = [];
    
$newvalues       = [];

    if (
in_array($fieldinfo['type'], array_merge($FIXED_LIST_FIELD_TYPES,[FIELD_TYPE_DATE_RANGE])))
        {
        
// Standard node fields
        // Set up arrays of node ids to add/remove and all new nodes.
        
$nodes_to_add    = [];
        
$nodes_to_remove = [];

        
// Get currently selected nodes for this field
        
$current_field_nodes get_resource_nodes($resource$fieldtrue);
        
$current_field_node_ids array_column($current_field_nodes,"ref");
        
// Get an 'existing' value
        
$existing implode(",",array_column($current_field_nodes,"path"));

        
// Get all node values into an array to search, not for dynamic keyword fields as these can be very long
        
if ($fieldinfo['type'] != FIELD_TYPE_DYNAMIC_KEYWORDS_LIST) {
            
$fieldnodes get_nodes($field,null,$fieldinfo['type'] == FIELD_TYPE_CATEGORY_TREE);
            
$nodes_by_ref = [];
            foreach (
$fieldnodes as $fieldnode) {
                
$nodes_by_ref[$fieldnode["ref"]] = $fieldnode;
            }
        }

        if(
$nodevalues)
            {
            
// List of node IDs has been passed in comma separated form, use them directly
            
$sent_nodes explode(",",$value);
            if (
                
in_array($fieldinfo['type'],[FIELD_TYPE_RADIO_BUTTONS,FIELD_TYPE_DROP_DOWN_LIST])
                && 
count($sent_nodes) > 1
            
) {
                
// Only a single value allowed
                
return false;
            }

            
// Validate each node
            
foreach($sent_nodes as $sent_node) {
                
$node_details = [];
                
$valid_node get_node($sent_node,$node_details);
                if (!
$valid_node || $node_details["resource_type_field"] !== $field) {
                    return 
false;
                }
                
$nodes_to_add[] = $sent_node;
                if (!
in_array($sent_node,$current_field_node_ids)) {
                    
$newnodes[] = $sent_node;
                }
            }

            
$nodes_to_remove array_diff($nodes_to_add,$current_field_node_ids);
            if(
count($nodes_to_add) != count($sent_nodes)) {
                
// Unable to find all node values that were passed
                
return false;
                }
            }
        else
            {
            
// Not a list of node IDs; value has been passed as normal string value
            // Get all the new values into an array
            
if(strpos($value,NODE_NAME_STRING_SEPARATOR) != false)
                {
                
$newvalues array_map('trim'explode(NODE_NAME_STRING_SEPARATOR$value));
                }
            else
                {
                if (
strlen($value) > && (($value[0] == "'" && $value[strlen($value)-1] == "'")
                    ||
                    (
$value[0] == "\"" && $value[strlen($value)-1] == "\""))
                    )
                    {
                    
// Quoted value - don't attempt to split on comma.
                    
$newvalues[] = substr($value,1,-1);
                    }
                else
                    {
                    
$newvalues trim_array(str_getcsv($value));
                    }
                }

            if(
$fieldinfo['type'] == FIELD_TYPE_DATE_RANGE)
                {
                
// Check it is in the correct format
                
$rangeregex="/^(\d{4})(-\d{2})?(-\d{2})?\/(\d{4})(-\d{2})?(-\d{2})?/";
                
// If this is a date range field we need to add values to the field options
                
if(!preg_match($rangeregex,$value,$matches))
                    {
                    
debug("ERROR - Invalid date range submitted: '" $value "'");
                    return 
false;
                    }

                
$rangedates array_map('trim'explode('/'$value));
                
$rangestart=str_pad($rangedates[0],  10"-00");
                
$rangeendparts=explode("-",$rangedates[1]);
                
$rangeendyear=$rangeendparts[0];
                
$rangeendmonth=isset($rangeendparts[1])?$rangeendparts[1]:12;
                
$rangeendday=isset($rangeendparts[2])?$rangeendparts[2]:cal_days_in_month(CAL_GREGORIAN$rangeendmonth$rangeendyear);
                
$rangeend=$rangeendyear "-" $rangeendmonth "-" $rangeendday;   
                
                
$current_dates array_column($fieldnodes,"ref","name");
                
$nodes_to_add[] = $current_dates[$rangestart] ?? set_node(null$fieldinfo["ref"], $rangestartnullnull);
                
$nodes_to_add[] = $current_dates[$rangeend] ?? set_node(null$fieldinfo["ref"], $rangeendnullnull);

                
$value $rangestart DATE_RANGE_SEPARATOR $rangeend;
                }
            elseif(
$fieldinfo['type'] == FIELD_TYPE_CATEGORY_TREE)
                {
                
// Values may have been passed as full paths or the individual node names
                // Create array with indexes as the values to look for
                
$nodes_available_keys  = [];
                
$nodes_available_lower_keys  = [];
                foreach(
$fieldnodes as $fieldnode)
                    {
                    
$nodes_available_keys[$fieldnode["path"]] = $fieldnode["ref"];
                    
$nodes_available_keys[$fieldnode["translated_path"]] = $fieldnode["ref"];
                    
$nodes_available_keys[$fieldnode["name"]] = $fieldnode["ref"];
                    
$nodes_available_keys[$fieldnode["translated_name"]] = $fieldnode["ref"];
                    
// Add case insensitive to check in case matching fails
                    
$nodes_available_lower_keys[mb_strtolower($fieldnode["path"])] = $fieldnode["ref"];
                    
$nodes_available_lower_keys[mb_strtolower($fieldnode["translated_path"])] = $fieldnode["ref"];
                    
$nodes_available_lower_keys[mb_strtolower($fieldnode["name"])] = $fieldnode["ref"];
                    
$nodes_available_lower_keys[mb_strtolower($fieldnode["translated_name"])] = $fieldnode["ref"];
                    }

                foreach(
$newvalues as $newvalue)
                    {
                    
$validval false;
                    
// Check if a full node path has been passed
                    
if (isset($nodes_available_keys[$newvalue])) {
                        
debug("update_field: Found node #" $newvalue  " for tree value: '" trim($newvalue) . "'");
                        
$nodes_to_add[] = $nodes_available_keys[$newvalue];
                        
$validval true;
                    } elseif (isset(
$nodes_available_lower_keys[mb_strtolower($newvalue)])) {
                        
debug("update_field: Found node #" $newvalue  " for tree value: '" trim($newvalue) . "'");
                        
$nodes_to_add[] = $nodes_available_lower_keys[$newvalue];
                        
$validval true;
                    }
                    if(!
$validval) {
                        
// Check for separate name values
                        
$splitvalues array_map('trim'explode('/'$newvalue));
                        foreach(
$splitvalues as $splitvalue) {
                            
# Check if each new value exists in current options list
                            
if (isset($nodes_available_keys[$splitvalue])) {
                                
debug("update_field: Found node # " $nodes_available_keys[$splitvalue]  . " for tree value: '" trim($splitvalue) . "'");
                                
$nodes_to_add[] = $nodes_available_keys[$splitvalue];
                                
$validval true;
                            } elseif (isset(
$nodes_available_lower_keys[mb_strtolower($splitvalue)])) {
                                
debug("update_field: Found node # " $nodes_available_lower_keys[$splitvalue]  . " for tree value: '" trim($splitvalue) . "'");
                                
$nodes_to_add[] = $nodes_available_lower_keys[$splitvalue];
                                
$validval true;
                            }
                        }
                    }
                    if(!
$validval)
                        {
                        
// Still not found - invalid option passed
                        
debug("update_field: " $newvalue " not found: in field tree");
                        return 
false;
                        }

                    
// Add all parent nodes
                    
if($category_tree_add_parents)
                        {
                        foreach(
$nodes_to_add as $node_to_add)
                            {
                            
$parent $nodes_by_ref[$node_to_add]["parent"];
                            while((int)
$parent 0)
                                {
                                if(isset(
$nodes_by_ref[$parent]))
                                    {
                                    
$nodes_to_add[] = $nodes_by_ref[$parent]["ref"];
                                    
$parent $nodes_by_ref[$parent]["parent"];
                                    }
                                else
                                    {
                                    
$parent 0;
                                    }
                                }
                            }
                        }
                    }
                }
            else
                {
                
// Check to see other nodes that need to be added
                
foreach ($newvalues as $newvalue) {
                    
$valuenode get_node_id($newvalue,$field);
                    if (
$valuenode) {
                        
// Add to array of nodes, unless it has been added to array already as a parent for a previous node
                        
if(!in_array($valuenode$nodes_to_add)) {
                            
$nodes_to_add[] = $valuenode;
                        }
                        if (!
in_array($valuenode,$current_field_node_ids)) {
                            
$newnodes[] = $valuenode;
                        }
                    } else {
                        
// Check for translated versions and different cases

                        
if ($fieldinfo['type'] == FIELD_TYPE_DYNAMIC_KEYWORDS_LIST) {
                            
// Special case for dynamic keywords as there will likely be a lot of them. Instead of getting and checking all of them,
                            // $fieldnodes to get subset of existing nodes for checking of language translations using like match by node name.
                            
$fieldnodes get_nodes($fieldnullfalsenullnull$newvaluefalsefalsefalse);
                        }

                        
$matchnode 0;
                        foreach(
$fieldnodes as $fieldnode) {
                            if (
                                
i18n_get_translated($fieldnode["name"]) == i18n_get_translated($newvalue)
                                && !
in_array($fieldnode["ref"], $nodes_to_add)
                            ) {
                                
$matchnode $fieldnode["ref"];
                                break;
                            } elseif (
                                
mb_strtolower(i18n_get_translated($fieldnode["name"])) == mb_strtolower(i18n_get_translated($newvalue))
                                && !
in_array($fieldnode["ref"], $nodes_to_add)
                            ) {
                                
// Check for node with same text in different case
                                
$matchnode $fieldnode["ref"];
                                break;
                            }
                        }

                        if (
$matchnode 0) {
                            if(!
in_array($matchnode$nodes_to_add)) {
                                
$nodes_to_add[] = $matchnode;
                            }
                            if (!
in_array($matchnode,$current_field_node_ids)) {
                                
$newnodes[] = $matchnode;
                            }
                        }
                        elseif (
$fieldinfo['type'] == FIELD_TYPE_DYNAMIC_KEYWORDS_LIST && !checkperm('bdk' $field)) {
                            
// Dynamic keyword, add as new node
                            // Append the option and update the field
                            
$newnode            set_node(null$fieldtrim($newvalue), nullnull);
                            
$nodes_to_add[]     = $newnode;
                            
debug("update_field: field option added: '" trim($newvalue));
                            
clear_query_cache("schema");
                        }
                    }
                } 
// End of foreach $newvalue
            
}
            
$nodes_to_remove array_diff($current_field_node_ids,$nodes_to_add);
        } 
// End of $nodevalues test


        // Now carry out the node additions and removals
        
if(count($nodes_to_add) > || count($nodes_to_remove) > 0)
            {
            
# Work out what nodes need to be added/removed/kept
            
$nodes_to_add       array_unique($nodes_to_add);
            
$added_nodes        array_diff($nodes_to_add,$current_field_node_ids);
            if(
in_array($fieldinfo['type'],[FIELD_TYPE_RADIO_BUTTONS,FIELD_TYPE_DROP_DOWN_LIST])
                &&
                (
count($added_nodes) + count($current_field_node_ids) - count($nodes_to_remove)) > 1)
                {
                
// Only a single value allowed
                
return false;
                }

            
// Update resource_node table and log
            
db_begin_transaction("update_field_{$field}");
            if(
count($nodes_to_remove)>0)
                {
                
delete_resource_nodes($resource,$nodes_to_remove,false);
                }
            if(
count($nodes_to_add)>0)
                {
                
add_resource_nodes($resource,$nodes_to_addfalse,false);
                }

            
// Update log
            
if($log && (count($nodes_to_add)>|| count($nodes_to_remove)>0))
                {
                
log_node_changes($resource,$nodes_to_add,$current_field_node_ids);
                
// Don't need to log this later
                
$log false;
                }

            
db_end_transaction("update_field_{$field}");

            if(
$fieldinfo['type']==FIELD_TYPE_CATEGORY_TREE)
                {
                
$all_treenodes get_cattree_nodes_ordered($field$resourcefalse); # True means get all nodes; False means get selected nodes
                
$treenodenames get_cattree_node_strings($all_treenodestrue); # True means names are paths to nodes; False means names are node names
                
$value implode(",",$treenodenames);
                
$data_joins_field_value implode($GLOBALS['field_column_string_separator'], $treenodenames);
                }
            else
                {
                
$node_names=[];
                foreach(
$nodes_to_add as $ref)
                    {
                    
$returned_node = [];
                    if(
get_node($ref,$returned_node))
                        {
                        
$node_names[] = $returned_node["name"];
                        }
                    }
                
$value implode(",",$node_names);
                
$data_joins_field_value implode($GLOBALS['field_column_string_separator'], $node_names);
                }
            } 
// End of adding/removing nodes
        
else
            {
            
// No node changes were made e.g. blocked adding new value with bdk permission. Nothing to log. Prevents resource_log()
            
$log false;
            }
        }
    else
        {
        
# Fetch previous value
        
$existing_resource_node get_resource_nodes($resource$fieldtrue)[0] ?? [];
        
$existing $existing_resource_node["name"] ?? "";
        if (
$value === $existing)
            {
            
// Nothing to do
            
return true;
            }

        if (
            
$GLOBALS['use_native_input_for_date_field']
            && 
$fieldinfo['type'] === FIELD_TYPE_DATE
            
&& $value !== ''
        
) {
            
// Establish whether date is a valid date or a valid date time
            
$value_valid_date_part=false;  
            if(
validateDatetime($value'Y-m-d')) {
                
$value_valid_date_part=true;  
            }
            elseif(
validateDatetime($value'Y-m-d H:i:s')) {
                
$value_valid_date_part=true;  
            }
            
// Return if there is no valid date part
            
if(!$value_valid_date_part) {
                
$errors[] = sprintf('%s: %s'i18n_get_translated($fieldinfo['title']), $lang['invalid_date_generic']);
                return 
false;
            }
            
// We only use the valid date part, so discard the time part if any
            
if($value_valid_date_part) {
                
$value_parts=explode(" ",$value);
                
$value=$value_parts[0];
            }
        }

        
$curnode $existing_resource_node["ref"] ?? ;
        if (
$curnode && get_nodes_use_count([$curnode]) == 1)
            {
            
// Reuse same node
            
set_node($curnode,$field,$value,null,0);
            }
        else
            {
            
// Remove node from resource and create new node
            
delete_resource_nodes($resource,[$curnode],false);
            
$savenode set_node(null,$field,$value,null,0);
            
add_resource_nodes($resource,[$savenode], truefalse);
            }
        }

    
# If this is a 'joined' field we need to add it to the resource column
    
$joins get_resource_table_joins();
    if(
in_array($fieldinfo['ref'],$joins))
        {
        
update_resource_field_column($resource,$field$data_joins_field_value);
        }

    
# Add any onchange code
    
if($fieldinfo["onchange_macro"]!="")
        {
        
$macro_resource_id=$resource;
        eval(
eval_check_signed($fieldinfo["onchange_macro"]));
        }

    
# Allow plugins to perform additional actions.
    // Log this update
    
if ($log && $value != $existing)
        {
        
resource_log($resource,LOG_CODE_EDITED,$field,"",$existing,unescape($value));
        }

    
# Allow plugins to perform additional actions.
    
hook("update_field","",array($resource,$field,$value,$existing,$fieldinfo,$newnodes,$newvalues));
    return 
true;
    }

This article was last updated 4th December 2024 08:35 Europe/London time based on the source file dated 28th November 2024 12:10 Europe/London time.