Collections functions
General functions
Node functions
Render functions
Theme permission functions
User functions
Resource 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 2532 to 2955

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 all node values into an array to search
        
$fieldnodes      get_nodes($field,null,$fieldinfo['type'] == FIELD_TYPE_CATEGORY_TREE);
      
        
// Get currently selected nodes for this field
        
$current_field_nodes get_resource_nodes($resource$fieldfalse);
        
$nodes_by_ref = [];
        foreach(
$fieldnodes as $fieldnode)
            {
            
$nodes_by_ref[$fieldnode["ref"]] = $fieldnode;
            }
        
// Get an 'existing' value
        
$existing_nodes array_intersect(array_column($fieldnodes,"ref"),$current_field_nodes);
        
$existing implode(",",array_column($existing_nodes,"path"));

        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;
                }

            foreach(
$fieldnodes as $fieldnode)
                {
                
// Add to array of nodes, unless it has been added to array already as a parent for a previous node
                
if (in_array($fieldnode["ref"],$sent_nodes) && !in_array($fieldnode["ref"],$nodes_to_add))
                    {
                    if(!
in_array($fieldnode["ref"],$current_field_nodes))
                        {
                        
$nodes_to_add[] = $fieldnode["ref"];
                        }
                    
$newnodes[] = $fieldnode["ref"];
                    }
                elseif(
in_array($fieldnode["ref"],$current_field_nodes) && !in_array($fieldnode["ref"],$sent_nodes))
                    {
                    
$nodes_to_remove[] = $fieldnode["ref"];
                    }
                }
            if(
count($newnodes) != 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)
                {
                
// Create array with indexes as the values to look for
                
$nodes_available_keys   = [];         
                foreach(
$fieldnodes as $fieldnode)
                    {
                    
$nodes_available_keys[mb_strtolower($fieldnode["path"])] = $fieldnode["ref"];
                    
$nodes_available_keys[mb_strtolower($fieldnode["translated_path"])] = $fieldnode["ref"];
                    
$nodes_available_keys[mb_strtolower($fieldnode["name"])] = $fieldnode["ref"];
                    
$nodes_available_keys[mb_strtolower($fieldnode["translated_name"])] = $fieldnode["ref"];
                    }                

                
$newvalues array_map('mb_strtolower'$newvalues);
                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;
                        }
                    
                    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;
                                }
                            }
                        }
                    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;
                                    }
                                }
                            }
                        }
                        
                    }
                }
            elseif(
$fieldinfo['type'] == FIELD_TYPE_DYNAMIC_KEYWORDS_LIST && !checkperm('bdk' $field))
                {
                
// If this is a dynamic keyword field need to add any new entries to the field nodes
                
$currentoptions = array();
                foreach(
$fieldnodes as $fieldnode)
                    {
                    
$fieldoptiontranslations explode('~'$fieldnode['name']);
                    if(
count($fieldoptiontranslations) < 2)
                        {
                        
$currentoptions[]=trim($fieldnode['name']); # Not a translatable field
                        
debug("update_field: current field option: '" trim($fieldnode['name']) . "'");
                        }
                    else
                        {
                        for (
$n=1;$n<count($fieldoptiontranslations);$n++)
                            {
                            
# Not a translated string, return as-is
                            
if (substr($fieldoptiontranslations[$n],2,1)!=":" && substr($fieldoptiontranslations[$n],5,1)!=":" && substr($fieldoptiontranslations[$n],0,1)!=":")
                                {
                                
$currentoptions[]=trim($fieldnode['name']);
                                
debug("update_field: current field option: '" $fieldnode['name']);
                                }
                            else
                                {
                                
# Support both 2 character and 5 character language codes (for example en, en-US).
                                
$p=strpos($fieldoptiontranslations[$n],':');
                                
$currentoptions[]=trim(substr($fieldoptiontranslations[$n],$p+1));
                                
debug("update_field: current field option: '" trim(substr($fieldoptiontranslations[$n],$p+1)));
                                }
                            }
                        }
                    }
                
                foreach(
$newvalues as $newvalue)
                    {
                    
# Check if each new value exists in current options list
                    
if(!in_array($newvalue$currentoptions) && $newvalue != '')
                        {
                        
# Append the option and update the field
                        
$newnode            set_node(null$fieldtrim($newvalue), nullnull);
                        
$nodes_to_add[]     = $newnode;
                        
$currentoptions[]   = trim($newvalue);
                        
$fieldnodes[]       = array("ref" => $newnode,"name" => trim($newvalue));
                        
debug("update_field: field option added: '" trim($newvalue));
                        
clear_query_cache("schema");
                        }
                    }
                } 
// End of FIELD_TYPE_DYNAMIC_KEYWORDS_LIST
           
            // Check to see other nodes that need to be added
            
$newvalues_translated $newvalues;
            
array_walk(
                
$newvalues_translated,
                function (&
$value$index)
                    {
                    
$value mb_strtolower(i18n_get_translated($value));
                    }
                );
        
            
// Set up array of nodes to remove
            
foreach($fieldnodes as $fieldnode)
                {
                
// Add to array of nodes, unless it has been added to array already as a parent for a previous node
                
if (in_array(mb_strtolower(i18n_get_translated($fieldnode["name"])), $newvalues_translated)
                    && !
in_array($fieldnode["ref"], $nodes_to_add)
                    )
                    {
                    
$nodes_to_add[] = $fieldnode["ref"];                  
                    }
                }

            
// Get all nodes to remove
            
foreach($fieldnodes as $fieldnode)
                {
                if(!
in_array($fieldnode["ref"], $nodes_to_add))
                    {
                    
$nodes_to_remove[] = $fieldnode["ref"];
                    }
                }     
            } 
// 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);
            
$nodes_to_remove    array_intersect(array_unique($nodes_to_remove),$current_field_nodes);
            
$added_nodes        array_diff($nodes_to_add,$current_field_nodes);
            
$removed_nodes      array_intersect($nodes_to_remove,$current_field_nodes);

            if(
in_array($fieldinfo['type'],[FIELD_TYPE_RADIO_BUTTONS,FIELD_TYPE_DROP_DOWN_LIST])
                &&
                (
count($added_nodes) + count($current_field_nodes) - count($removed_nodes)) > 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_nodes);
                
// 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);
                }
            }
        }
    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 !== ''
            
&& !validateDatetime($value'Y-m-d')
        )
            {
            
$errors[] = sprintf('%s: %s'i18n_get_translated($fieldinfo['title']), $lang['invalid_date_generic']);
            return 
false;
            }

        
$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 19th March 2024 08:35 Europe/London time based on the source file dated 11th March 2024 14:25 Europe/London time.