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

save_resource_data()

Description

Save resource data

IMPORTANT: inactive nodes should be left alone (don't add/remove) except when processing fixed list field types that
only hold one value (dropdown, radio). Plugins should determine this based on their use cases when hooking.

Parameters

ColumnTypeDefaultDescription
$ref int
$multi bool
$autosave_field string|int ""

Return

true|array List of errors if unsuccessful, true otherwise

Location

include/resource_functions.php lines 685 to 1410

Definition

 
function save_resource_data($ref,$multi,$autosave_field="")
    {
    
debug_function_call("save_resource_data"func_get_args());
    
# Save all submitted data for resource $ref.
    # Also re-index all keywords from indexable fields.
    
global $lang$languages$language$FIXED_LIST_FIELD_TYPES,
           
$DATE_FIELD_TYPES$reset_date_field$reset_date_upload_template,
           
$edit_contributed_by$new_checksums$upload_review_mode$blank_edit_template$is_template$NODE_FIELDS,
           
$userref$userresourcedefaults;

    
hook("befsaveresourcedata""", array($ref));
    
// Ability to avoid editing conflicts by checking checksums.
    // NOTE: this should NOT apply to upload.
    
$check_edit_checksums true;

    
// Save resource defaults (functionality available for upload only)
    // Call it here so that if users have access to the field and want
    // to override it, they can do so
    
if($ref)
        {
        
set_resource_defaults($ref);

        
$check_edit_checksums false;
        }

    
# Loop through the field data and save (if necessary)
    
$errors=array();
    
$fields=get_resource_field_data($ref,$multi, !hook("customgetresourceperms"));

    
$expiry_field_edited=false;
    
$resource_data=get_resource_data($ref);

    if(
$resource_data["lock_user"] > && $resource_data["lock_user"] != $userref)
        {
        
$errors[] = get_resource_lock_message($resource_data["lock_user"]);
        return 
$errors;
        }

    
# Load the configuration for the selected resource type. Allows for alternative notification addresses, etc.
    
resource_type_config_override($resource_data["resource_type"]);

    
# Set up arrays of node ids to add/remove. We can't remove all nodes as user may not have access
    
$nodes_to_add               = [];
    
$nodes_to_remove            = [];
    
$oldnodenames               = [];
    
$nodes_check_delete         = [];
    
$resource_update_log_sql    = [];
    
$ui_selected_node_values    = [];
    
$all_current_field_nodes    = [];
    
$new_node_values            = [];
    
$updated_resources          = [];

    
$node_not_active = fn(array $node): bool => !node_is_active($node);

    
// All the nodes passed for editing. Some of them were already a value
    // of the fields while others have been added/removed
    
$user_set_values getval('nodes', [], false'is_array');

    
// Initialise array to store new checksums that client needs after autosave, without which subsequent edits will fail
    
$new_checksums = array();
    for (
$n=0;$n<count($fields);$n++)
        {
        if(!(
            
checkperm('F' $fields[$n]['ref'])
            || (
checkperm("F*") && !checkperm('F-' $fields[$n]['ref']))
            
// If we hide on upload the field, there is no need to check values passed from the UI as there shouldn't be any
            
|| (($ref || $upload_review_mode) && $fields[$n]['hide_when_uploading'])
            )
            && (
'' == $autosave_field || $autosave_field == $fields[$n]['ref']
                || (
is_array($autosave_field) && in_array($fields[$n]['ref'], $autosave_field))
            )
        )
            {
            
// Fixed list  fields use node IDs directly
            
if(in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES))
                {
                
debug("save_resource_data(): Checking nodes to add/ remove for field {$fields[$n]['ref']} - {$fields[$n]['title']}");

                
// Get currently selected nodes for this field
                
$current_field_nodes get_resource_nodes($ref$fields[$n]['ref']);
                
$all_current_field_nodes array_merge($all_current_field_nodes,$current_field_nodes);
                
// Check if resource field data has been changed between form being loaded and submitted
                
$post_cs getval("field_" $fields[$n]['ref'] . "_checksum","");
                
sort($current_field_nodes);
                
$current_cs md5(implode(",",$current_field_nodes));
                if(
$check_edit_checksums && $post_cs != "" && $post_cs != $current_cs)
                    {
                    
$errors[$fields[$n]["ref"]] = i18n_get_translated($fields[$n]['title']) . ': ' $lang["save-conflict-error"];
                    continue;
                    }

                
debug("save_resource_data(): Current nodes for resource " $ref ": " implode(",",$current_field_nodes));

                
// Work out nodes submitted by user
                
if(isset($user_set_values[$fields[$n]['ref']])
                    && !
is_array($user_set_values[$fields[$n]['ref']])
                    && 
'' != $user_set_values[$fields[$n]['ref']]
                    && 
is_numeric($user_set_values[$fields[$n]['ref']]))
                    {
                    
$ui_selected_node_values[] = $user_set_values[$fields[$n]['ref']];
                    }
                elseif(isset(
$user_set_values[$fields[$n]['ref']])
                    && 
is_array($user_set_values[$fields[$n]['ref']]))
                    {
                    
$ui_selected_node_values $user_set_values[$fields[$n]['ref']];
                    }
                
// Check nodes are valid for this field
                
if(FIELD_TYPE_CATEGORY_TREE === $fields[$n]['type'])
                    {
                    
$all_tree_nodes_ordered get_cattree_nodes_ordered($fields[$n]['ref'], nulltrue);
                    
// remove the fake "root" node which get_cattree_nodes_ordered() is adding since we won't be using get_cattree_node_strings()
                    
array_shift($all_tree_nodes_ordered);
                    
$inactive_nodes array_column(array_filter($all_tree_nodes_ordered$node_not_active), 'ref');
                    
$all_tree_nodes_ordered array_values($all_tree_nodes_ordered);

                    
$node_options array_column($all_tree_nodes_ordered'name''ref');
                    
$validnodes array_keys($node_options);
                    }
                else
                    {
                    
$fieldnodes   get_nodes($fields[$n]['ref'], ''false);
                    
$node_options array_column($fieldnodes'name''ref');
                    
$validnodes   array_column($fieldnodes'ref');
                    
$inactive_nodes array_column(array_filter($fieldnodes$node_not_active), 'ref');
                    }

                
// $validnodes are already sorted by the order_by (default for get_nodes). This is needed for the data_joins fields later
                
$ui_selected_node_values array_values(array_intersect($validnodes$ui_selected_node_values));
                
debug("save_resource_data(): UI selected nodes for resource {$ref}: " implode(','$ui_selected_node_values));

                
// Set new value for logging
                
$new_node_values array_merge($new_node_values$ui_selected_node_values);

                
$added_nodes array_diff($ui_selected_node_values$current_field_nodes$inactive_nodes);
                
debug("save_resource_data(): Adding nodes to resource " $ref ": " implode(",",$added_nodes));
                
$nodes_to_add array_merge($nodes_to_add$added_nodes);

                if (
                    
// We must release an inactive node if the type can only hold one value...
                    
in_array($fields[$n]['type'], [FIELD_TYPE_DROP_DOWN_LISTFIELD_TYPE_RADIO_BUTTONS])
                    
// ...but prevent direct removals (ie. no value)
                    
&& $ui_selected_node_values !== []
                ) {
                    
$removed_nodes array_diff($current_field_nodes$ui_selected_node_values);
                    
$current_inactive_resource_field_nodes = [];
                } else {
                    
$removed_nodes array_diff($current_field_nodes$ui_selected_node_values$inactive_nodes);
                    
$current_inactive_resource_field_nodes array_intersect($current_field_nodes$inactive_nodes);
                }
                
debug("save_resource_data(): Removed nodes from resource " $ref ": " implode(",",$removed_nodes));
                
$nodes_to_remove array_merge($nodes_to_remove$removed_nodes);

                if(
count($added_nodes) > || count($removed_nodes) > 0)
                    {
                    
$new_nodevals = array();
                    
// Build new value
                    
foreach($ui_selected_node_values as $ui_selected_node_value)
                        {
                        if(
FIELD_TYPE_CATEGORY_TREE === $fields[$n]['type'])
                            {
                            
$new_nodevals[] = implode(
                                
'/',
                                
array_column(
                                    
compute_node_branch_path($all_tree_nodes_ordered$ui_selected_node_value),
                                    
'name'
                                
)
                            );
                            continue;
                            }

                        
$new_nodevals[] = $node_options[$ui_selected_node_value];
                        }
                    
# Is this is a 'joined' field?
                    
$joins=get_resource_table_joins();
                    if (
in_array($fields[$n]["ref"],$joins))
                        {
                        
$new_nodes_val implode($GLOBALS['field_column_string_separator'], $new_nodevals);
                        if ((
== $fields[$n]['required'] && "" != $new_nodes_val) || == $fields[$n]['required']) # If joined field is required we shouldn't be able to clear it.
                            
{
                            
update_resource_field_column($ref,$fields[$n]["ref"],$new_nodes_val);
                            }
                        }
                    
$val implode(",",$new_nodevals);
                    
$ui_selected_node_values array_merge($ui_selected_node_values$current_inactive_resource_field_nodes);
                    
sort($ui_selected_node_values);
                    
$new_checksums[$fields[$n]['ref']] = md5(implode(',',$ui_selected_node_values));
                    
$updated_resources[$ref][$fields[$n]['ref']] = $new_nodevals// To pass to hook
                    
}
                else
                    {
                    
$val "";
                    }
                } 
// End of if in $FIXED_LIST_FIELD_TYPES
            
else
                {
                if(
$fields[$n]['type']==FIELD_TYPE_DATE_RANGE)
                    {
                    
# date range type
                    # each value will be a node so we end up with a pair of nodes to represent the start and end dates

                    
$daterangenodes=array();
                    
$newval="";

                    if((
$date_edtf=getval("field_" $fields[$n]["ref"] . "_edtf",""))!=="")
                        {
                        
// We have been passed the range in EDTF format, check it is in the correct format
                        
$rangeregex="/^(\d{4})(-\d{2})?(-\d{2})?\/(\d{4})(-\d{2})?(-\d{2})?/";
                        if(!
preg_match($rangeregex,$date_edtf,$matches))
                            {
                            
$errors[$fields[$n]["ref"]] = $lang["information-regexp_fail"] . " : " $date_edtf;
                            continue;
                            }
                        if(
is_int_loose($fields[$n]["linked_data_field"]))
                            {
                            
// Update the linked field with the raw EDTF string submitted
                            
update_field($ref,$fields[$n]["linked_data_field"],$date_edtf);
                            }
                        
$rangedates explode("/",$date_edtf);
                        
$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;

                        
$newval $rangestart DATE_RANGE_SEPARATOR $rangeend;
                        
$daterangenodes[]=set_node(null$fields[$n]["ref"], $rangestartnullnull);
                        
$daterangenodes[]=set_node(null$fields[$n]["ref"], $rangeendnullnull);
                        }
                    else
                        {
                        
// Range has been passed via normal inputs, construct the value from the date/time dropdowns
                        
$date_parts=array("_start","_end");

                        foreach(
$date_parts as $date_part)
                            {
                            
$val getval("field_" $fields[$n]["ref"] . $date_part "-y","");
                            if (
intval($val)<=0)
                                {
                                
$val="";
                                }
                            elseif ((
$field=getval("field_" $fields[$n]["ref"] . $date_part "-m",""))!="")
                                {
                                
$val.="-" $field;
                                if ((
$field=getval("field_" $fields[$n]["ref"] . $date_part "-d",""))!="")
                                    {
                                    
$val.="-" $field;
                                    }
                                    else
                                    {
                                    
$val.="-00";
                                    }
                                }
                            else
                                {
                                
$val.="-00-00";
                                }

                            
$newval.= ($newval != "" DATE_RANGE_SEPARATOR "") . $val;
                            if(
$val!=="")
                                {
                                
$daterangenodes[]=set_node(null$fields[$n]["ref"], $valnullnull);
                                }
                            }
                        }
                    
natsort($daterangenodes);

                    
// Set new value for logging
                    
$new_node_values array_merge($new_node_values,$daterangenodes);

                    
// Get currently selected nodes for this field
                    
$current_field_nodes get_resource_nodes($ref$fields[$n]['ref'], falseSORT_ASC);
                    
$all_current_field_nodes array_merge($all_current_field_nodes,$current_field_nodes);

                        
// Check if resource field data has been changed between form being loaded and submitted
                        
$post_cs getval("field_" $fields[$n]['ref'] . "_checksum","");
                        
sort($current_field_nodes);
                        
$current_cs md5(implode(",",$current_field_nodes));
                        if(
$check_edit_checksums && $post_cs != "" && $post_cs != $current_cs)
                            {
                            
$errors[$fields[$n]["ref"]] = i18n_get_translated($fields[$n]['title']) . ': ' $lang["save-conflict-error"];
                            continue;
                            }

                    if(
$daterangenodes !== $current_field_nodes)
                        {
                        
$added_nodes array_diff($daterangenodes$current_field_nodes);
                        
debug("save_resource_data(): Adding nodes to resource " $ref ": " implode(",",$added_nodes));
                        
$nodes_to_add array_merge($nodes_to_add$added_nodes);
                        
$removed_nodes array_diff($current_field_nodes,$daterangenodes);
                        
debug("save_resource_data(): Removed nodes from resource " $ref ": " implode(",",$removed_nodes));
                        
$nodes_to_remove array_merge($nodes_to_remove$removed_nodes);

                        
$val $newval;
                        
# If this is a 'joined' field it still needs to be added to the resource column
                        
$joins=get_resource_table_joins();
                        if (
in_array($fields[$n]["ref"],$joins))
                            {
                            
update_resource_field_column($ref,$fields[$n]["ref"],$newval);
                            }
                        
sort($daterangenodes);
                        
$new_checksums[$fields[$n]['ref']] = md5(implode(",",$daterangenodes));
                        
$updated_resources[$ref][$fields[$n]['ref']][] = $newval// To pass to hook
                        
}
                    }
                elseif(
in_array($fields[$n]['type'], $DATE_FIELD_TYPES))
                    {
                    
# date type, construct the value from the date/time dropdowns to be used in DB
                    
$val=sanitize_date_field_input($fields[$n]["ref"], false);

                    
// A proper input:date field
                    
if ($GLOBALS['use_native_input_for_date_field'] && $fields[$n]['type'] === FIELD_TYPE_DATE)
                        {
                        
$val getval("field_{$fields[$n]['ref']}"'');
                        if(
$val !== '' && !validateDatetime($val'Y-m-d'))
                            {
                            
$errors[$fields[$n]['ref']] = $lang['error_invalid_date'] . ' : ' $val;
                            continue;
                            }
                        }

                    
// Upload template: always reset to today's date, if configured and field is hidden
                    
if($ref
                        
&& $reset_date_upload_template
                        
&& $reset_date_field == $fields[$n]['ref']
                        && 
$fields[$n]['hide_when_uploading']
                    )
                        {
                        
$val date('Y-m-d H:i');
                        }

                    
// Check if resource field data has been changed between form being loaded and submitted
                    
$post_cs getval("field_" $fields[$n]['ref'] . "_checksum","");
                    
$current_cs md5((string)$fields[$n]['value']);
                    if(
$check_edit_checksums && $post_cs != "" && $post_cs != $current_cs)
                        {
                        
$errors[$fields[$n]["ref"]] = i18n_get_translated($fields[$n]['title']) . ': ' $lang["save-conflict-error"];
                        continue;
                        }

                    
$new_checksums[$fields[$n]['ref']] = md5($val);
                    
$updated_resources[$ref][$fields[$n]['ref']][] = $val// To pass to hook
                    
}
                else
                    {
                    
# Set the value exactly as sent.
                    
$val=getval("field_" $fields[$n]["ref"],"");
                    
$rawval getval("field_" $fields[$n]["ref"],"");
                    
# Check if resource field data has been changed between form being loaded and submitted
                    # post_cs is the checksum of the data when it was loaded from the database
                    # current_cs is the checksum of the data on the database now
                    # if they are the same then there has been no intervening update and so its ok to update with our new value
                    # if our new data yields a different checksum, then we know the new value represents a change
                    # the new checksum for the new value of a field is stored in $new_checksums[$fields[$n]['ref']]
                    
$post_cs getval("field_" $fields[$n]['ref'] . "_checksum","");
                    
$current_cs md5(trim(preg_replace('/\s\s+/'' ', (string) $fields[$n]['value'])));

                    if(
$check_edit_checksums && $post_cs != "" && $post_cs != $current_cs)
                        {
                        
$errors[$fields[$n]["ref"]] = i18n_get_translated($fields[$n]['title']) . ': ' $lang["save-conflict-error"];
                        continue;
                        }
                    
$new_checksums[$fields[$n]['ref']] = md5(trim(preg_replace('/\s\s+/'' '$rawval)));
                    
$updated_resources[$ref][$fields[$n]['ref']][] = $val// To pass to hook
                    
}

                
# Check for regular expression match
                
if (strlen(trim((string)$fields[$n]["regexp_filter"]))>=&& strlen((string) $val)>0)
                    {
                    global 
$regexp_slash_replace;
                    if(
preg_match("#^" str_replace($regexp_slash_replace'\\',$fields[$n]["regexp_filter"]) . "$#",$val,$matches)<=0)
                        {
                        global 
$lang;
                        
debug($lang["information-regexp_fail"] . ": -" "reg exp: " str_replace($regexp_slash_replace'\\',$fields[$n]["regexp_filter"]) . ". Value passed: " $val);
                        
$errors[$fields[$n]["ref"]]=$lang["information-regexp_fail"] . " : " $val;
                        continue;
                        }
                    }
                
$modified_val=hook("modifiedsavedfieldvalue",'',array($fields,$n,$val));
                if(!empty(
$modified_val))
                    {
                    
$val=$modified_val;
                    
$new_checksums[$fields[$n]['ref']] = md5(trim(preg_replace('/\s\s+/'' '$val)));
                    }

                
$error hook("additionalvalcheck""all", array($fields$fields[$n]));
                if(
$error)
                    {
                    
$errors[$fields[$n]["ref"]]=$error;
                    continue;
                    }
                } 
// End of if not a fixed list field

            // Determine whether a required field has a default for the user
            
$field_has_default_for_user=false;
            if(
$userresourcedefaults != '')
                {
                foreach(
explode(';'$userresourcedefaults) as $rule)
                    {
                    
$rule_detail         explode('='trim($rule));
                    
$field_shortname     $rule_detail[0];
                    
$field_default_value $rule_detail[1];
                    if(
$field_shortname  == $fields[$n]['name'] && $field_default_value !=""
                        {
                        
$field_has_default_for_user=true;
                        break;
                        }
                    }
                }

            
// Populate empty field with the default if necessary
            
if($field_has_default_for_user && strlen((string) $val)==0) {
                
$val=$field_default_value;
                
$new_checksums[$fields[$n]['ref']] = md5(trim(preg_replace('/\s\s+/'' '$val)));
            }

            if( 
$fields[$n]['required'] == 1
                
&& check_display_condition($n$fields[$n], $fieldsfalse$ref)
                && (
                    
// Required node field with no nodes submitted is a candidate for error
                    
(in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && count($ui_selected_node_values) == 0)
                    
// Required continuous field with no value is a candidate for error
                    
|| (!in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && trim(strip_leading_comma($val)) == '')
                )
                && (
                    
// An existing resource node field with neither any nodes submitted nor a resource default
                    
($ref && in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && count($ui_selected_node_values) == && !$field_has_default_for_user)
                    
// An existing resource continuous field with neither an input value nor a resource default
                    
|| ($ref && !in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && strlen((string) $val)==&& !$field_has_default_for_user)
                    
// A template node field with neither any nodes submitted nor a resource default
                    
|| ($ref && in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && count($ui_selected_node_values) == && !$field_has_default_for_user)
                    
// A template continuous field with neither an input value nor a resource default
                    
|| ($ref && !in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && strlen((string) $val)==&& !$field_has_default_for_user)
                )
                
// Not a metadata template
                
&& !$is_template
            
)
                {
                
$field_visibility_status=getval("field_".$fields[$n]['ref']."_displayed","");
                
# Register an error only if the empty required field was actually displayed
                
if (is_field_displayed($fields[$n]) && $field_visibility_status=="block")
                    {
                    
$errors[$fields[$n]['ref']] = i18n_get_translated($fields[$n]['title']) . ": {$lang['requiredfield']}";
                    continue;
                    }
                }

            
// If all good so far, then save the data
            
if(
                
in_array($fields[$n]['type'], NON_FIXED_LIST_SINGULAR_RESOURCE_VALUE_FIELD_TYPES)
                && 
str_replace("\r\n""\n"trim((string) $fields[$n]['value'])) !== str_replace("\r\n""\n"trim((string) $val))
            )
                {
                
# This value is different from the value we have on record.
                # Expiry field? Set that expiry date(s) have changed so the expiry notification flag will be reset later in this function.
                
if ($fields[$n]["type"]==FIELD_TYPE_EXPIRY_DATE)
                    {
                    
$expiry_field_edited=true;
                    }

                
$use_node null;
                if(
trim((string) $fields[$n]["nodes"]) != "")
                    {
                    
// Remove any existing node IDs for this non-fixed list field (there should only be one) unless used by other resources.
                    
$current_field_nodes array_filter(explode(",",$fields[$n]["nodes"]),"is_int_loose");
                    
$all_current_field_nodes array_merge($all_current_field_nodes,$current_field_nodes);
                    foreach(
$current_field_nodes as $current_field_node)
                        {
                        
$inuse get_nodes_use_count([$current_field_node]);
                        
$inusecount $inuse[$current_field_node] ?? 0;
                        if (
$current_field_node && $inusecount == 1)
                            {
                            
// Reuse same node
                            
$use_node $current_field_node;
                            }
                        else
                            {
                            
// Remove node from resource and create new node
                            
$nodes_to_remove[] = $current_field_node;
                            
$nodes_check_delete[] = $current_field_node;
                            }
                        }
                    }

                
# Add new node unless empty string
                
if($val == '')
                    {
                    
// Remove and delete node
                    
$nodes_to_remove[] = $current_field_node;
                    
$nodes_check_delete[] = $current_field_node;
                    }
                else
                    {
                    
// Update the existing node
                    
$newnode set_node($use_node$fields[$n]["ref"], $valnullnull);
                    if((int)
$newnode != (int)$use_node)
                        {
                        
// Node already exists, remove current node and replace
                        
$nodes_to_add[] = $newnode;
                        
$nodes_to_remove[] = $use_node;
                        
$nodes_check_delete[]=$use_node;
                        
// Set new value for logging
                        
$new_node_values[] = $newnode;
                        }
                    else
                        {
                        
$new_node_values[] = $use_node;
                        }

                    
// Add to array for logging
                    
if (!is_null($use_node))
                        {
                        
$oldnodenames[$use_node] = $fields[$n]['value'];
                        }
                    }

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

                }

            
# Add any onchange code if new checksum for field shows that it has changed
            
if(isset($fields[$n]["onchange_macro"]) && $fields[$n]["onchange_macro"]!=="" 
                    
&& $post_cs !==""
                    
&& isset($new_checksums[$fields[$n]["ref"]]) 
                    && 
$post_cs !== $new_checksums[$fields[$n]["ref"]])
                {
                
$macro_resource_id=$ref;
                eval(
eval_check_signed($fields[$n]["onchange_macro"]));
                }

            } 
# End of if "allowed to edit field conditions"        
        
# End of for $fields

    // When editing a resource, prevent applying the change to the resource if there are any errors
    
if(count($errors) > && $ref 0)
        {
        return 
$errors;
        }

   
# Save related resource field if value for Related input field is autosaved, or if form has been submitted by user
    
if (($autosave_field=="" || $autosave_field=="Related") && isset($_POST["related"]))
        {
        
# save related resources field
        
$related=explode(",",getval("related",""));
        
# Trim whitespace from each entry
        
foreach ($related as &$relatedentry)
            {
            
$relatedentry trim($relatedentry);
            }
        
# Make sure all submitted values are numeric
        
$to_relate array_filter($related,"is_int_loose");

        
$currently_related get_related_resources($ref);
        
$to_add array_diff($to_relate$currently_related);
        
$to_delete array_diff($currently_related$to_relate);

        if(
count($to_add) > 0)
            {
            
update_related_resource($ref$to_addtrue);
            }
        if(
count($to_delete) > 0)
            {
            
update_related_resource($ref$to_deletefalse);
            }
        }

    
// Update resource_node table
    
db_begin_transaction("update_resource_node");
    if(
count($nodes_to_remove)>0)
        {
        
delete_resource_nodes($ref,$nodes_to_removefalse);
        }

    if(
count($nodes_to_add)>0)
        {
        
add_resource_nodes($ref,$nodes_to_addfalsefalse);
        }
    
log_node_changes($ref,$new_node_values$all_current_field_nodes,"",$oldnodenames);

    if(
count($nodes_check_delete)>0)
        {
        
// This has to be after call to log_node_changes() or nodes cannot be resolved
        
check_delete_nodes($nodes_check_delete);
        }

    
db_end_transaction("update_resource_node");

    
// Autocomplete any blank fields without overwriting any existing metadata
    
$autocomplete_fields autocomplete_blank_fields($reffalsetrue);
    foreach(
$autocomplete_fields as $autocomplete_field_ref => $autocomplete_field_value)
        {
        
$new_checksums[$autocomplete_field_ref] = md5((string)$autocomplete_field_value);
        }

    
// Initialise an array of updates for the resource table
    
$resource_update_sql = array();
    
$resource_update_params = array();
    if(
$edit_contributed_by)
        {
        
$created_by $resource_data['created_by'];
        
$new_created_by getval("created_by",0,true);
        if((
getval("created_by",0,true) > 0) && $new_created_by != $created_by)
            {
            
# Also update created_by
            
$resource_update_sql[] = "created_by= ?";
            
$resource_update_params[]="i";$resource_update_params[]=$new_created_by;
            
$olduser=get_user($created_by);
            
$newuser=get_user($new_created_by);
            
$resource_update_log_sql[] = array(
                    
"ref"=>$ref,
                    
"type"=>LOG_CODE_CREATED_BY_CHANGED,
                    
"field"=>0,
                    
"notes"=>"",
                    
"from"=>$created_by " (" . ($olduser["fullname"]=="" $olduser["username"] : $olduser["fullname"])  . ")","to"=>$new_created_by " (" . ($newuser["fullname"]=="" $newuser["username"] : $newuser["fullname"])  . ")");
            }
        }

    
# Expiry field(s) edited? Reset the notification flag so that warnings are sent again when the date is reached.
    
if ($expiry_field_edited)
        {
        
$resource_update_sql[] = "expiry_notification_sent='0'";
        }

    if (!
hook('forbidsavearchive''', array($errors)))
        {
        
# Also update archive status and access level
        
$oldaccess=$resource_data['access'];
        
$access=getval("access",$oldaccess,true);

        
$oldarchive=$resource_data['archive'];
        
$setarchivestate=getval("status",$oldarchive,true);
        if(
$setarchivestate!=$oldarchive && !checkperm("e" $setarchivestate)) // don't allow change if user has no permission to change archive state
            
{
            
$setarchivestate=$oldarchive;
            }

        
// Only if changed
        
if(($autosave_field=="" || $autosave_field=="Status") && $setarchivestate != $oldarchive)
            {
            
// Check if resource status has already been changed between form being loaded and submitted
            
if(getval("status_checksum","") != "" && getval("status_checksum","") != $oldarchive)
                {
                
$errors["status"] = $lang["status"] . ': ' $lang["save-conflict-error"];
                }
            else
                {
                
// update archive status if different (doesn't matter whether it is a user template or a genuine resource)
                
if($setarchivestate != $oldarchive)
                    {
                    
update_archive_status($ref,$setarchivestate,array($oldarchive));
                    }

                
$new_checksums["status"] = $setarchivestate;
                }
            }

        if((
$autosave_field=="" || $autosave_field=="Access") && $access != $oldaccess)
            {
            
// Check if resource access has already been changed between form being loaded and submitted
            
if(getval("access_checksum","") != "" && getval("access_checksum","") != $oldaccess)
                {
                
$errors["access"] = $lang["access"] . ': ' $lang["save-conflict-error"];
                }
            else
                {
                
$resource_update_sql[] = "access= ?";
                
$resource_update_params[]="i";$resource_update_params[]=$access;
                if(
$access != $oldaccess && $ref)
                    {
                    
$resource_update_log_sql[] = array(
                        
'ref'   => $ref,
                        
'type'  => 'a',
                        
'field' => 0,
                        
'notes' => '',
                        
'from'  => $oldaccess,
                        
'to'    => $access);
                    }

                if (
$oldaccess==&& $access!=3)
                    {
                    
# Moving out of the custom state. Delete any usergroup specific access.
                    # This can delete any 'manual' usergroup grants also as the user will have seen this as part of the custom access.
                    
delete_resource_custom_access_usergroups($ref);
                    }
                
$new_checksums["access"] = $access;
                }
            }
        }

    if(
count($resource_update_sql)>0)
        {
        
$sql "UPDATE resource SET " implode(",",$resource_update_sql) . " WHERE ref=?";
        
$sqlparams array_merge($resource_update_params,["i",$ref]);
        
ps_query($sql,$sqlparams);
        }

    foreach(
$resource_update_log_sql as $log_sql)
        {
        
resource_log($log_sql["ref"],$log_sql["type"],$log_sql["field"],$log_sql["notes"],$log_sql["from"],$log_sql["to"]);
        }

    
# Save any custom permissions
    
if (getval("access",0)==RESOURCE_ACCESS_CUSTOM_GROUP)
        {
        
save_resource_custom_access($ref);
        }

    
// Plugins can do extra actions once all fields have been saved and return errors back if needed
    
$plg_errors hook('aftersaveresourcedata''', array($ref$nodes_to_add$nodes_to_remove$autosave_field$fields,$updated_resources));
    if(
is_array($plg_errors) && !empty($plg_errors))
        {
        
$errors array_merge($errors$plg_errors);
        }

    if (
count($errors)==0)
        {
        
daily_stat("Resource edit"$ref);
        return 
true;
        }
    return 
$errors;
    }

This article was last updated 8th December 2024 20:35 Europe/London time based on the source file dated 6th December 2024 14:05 Europe/London time.