@@ -1581,6 +1581,8 @@ public static function getChangedFieldsSinceLastRender($form_id, $view_id, $subm
15811581 break ;
15821582 }
15831583 }
1584+
1585+ // currently file conficts are ignored: the latest file is always overridden
15841586 list ($ user_value , $ file_field ) = self ::getSaveFieldValueFromUpdateRequest ($ post , $ form_field , $ field_settings , $ field_types_processing_info );
15851587
15861588 $ changed [$ field_name ] = array (
@@ -1594,6 +1596,155 @@ public static function getChangedFieldsSinceLastRender($form_id, $view_id, $subm
15941596 }
15951597
15961598
1599+ /**
1600+ * Used for clients and administrators when updating a submission. This checks the specific submission data hadn't
1601+ * changed while they were editing (i.e. the actual changed fields, not the general submission itself). If it does
1602+ * it handles returning the list of changed fields for users to reconcile the conflicts manually.
1603+ * @param $form_id
1604+ * @param $submission_id
1605+ * @param $view_id
1606+ * @param $editable_field_ids
1607+ * @param $request
1608+ * @return array
1609+ */
1610+ public static function updateSubmissionWithConflictDetection ($ form_id , $ submission_id , $ view_id , $ editable_field_ids , $ request )
1611+ {
1612+ $ L = Core::$ L ;
1613+
1614+ $ success = true ;
1615+ $ message = "" ;
1616+ $ changed_fields = array ();
1617+ $ failed_validation = false ;
1618+
1619+ if (isset ($ _POST ["core__reconcile_changed_fields " ])) {
1620+ $ state = Sessions::get ("last_edit_submission_state " );
1621+
1622+ // filter out anything with "db value" - we don't care about them any more: the user has indicated they want the
1623+ // value from the DB, so even if it's changed again, just use it
1624+ $ keys = array_keys ($ state ["data " ]);
1625+ $ fields_to_update = array ();
1626+ $ user_values = Sessions::get ("conflicted_user_values " );
1627+
1628+ $ view_fields = Submissions::getSubmissionByField ($ form_id , $ submission_id , $ view_id );
1629+ foreach ($ keys as $ field_name ) {
1630+ if ($ request [$ field_name ] == "user_value " ) {
1631+ $ fields_to_update [] = $ field_name ;
1632+ $ request [$ field_name ] = $ user_values [$ field_name ]["user_value " ];
1633+ } else {
1634+ $ request [$ field_name ] = $ view_fields [$ field_name ];
1635+ }
1636+ }
1637+
1638+ if (empty ($ fields_to_update )) {
1639+ $ success = true ;
1640+ $ message = $ L ["notify_differences_resolved " ];
1641+ } else {
1642+ $ changed_fields = Submissions::getChangedFieldsSinceLastRender ($ form_id , $ view_id , $ submission_id , $ request ["tab " ], $ request );
1643+
1644+ // now if the old DB values are the same as what they already reviewed, that's fine, we can just update the record.
1645+ // But if it changed again, display the conflict resolution page with the latest info.
1646+ $ db_values_same = true ;
1647+ foreach ($ changed_fields as $ field_name => $ changes ) {
1648+ if ($ user_values [$ field_name ]["db_value " ] !== $ changes ["db_value " ]) {
1649+ $ db_values_same = false ;
1650+ } else {
1651+ $ request [$ field_name ] = $ changes ["user_value " ];
1652+ }
1653+ }
1654+
1655+ if ($ db_values_same ) {
1656+ $ changed_fields = array ();
1657+ Sessions::set ("new_search " , "yes " );
1658+ $ request ["view_id " ] = $ view_id ;
1659+ $ request ["editable_field_ids " ] = $ editable_field_ids ;
1660+ list ($ success , $ message ) = Submissions::updateSubmission ($ form_id , $ submission_id , $ request , false );
1661+ }
1662+ }
1663+
1664+ } else {
1665+ // see if any of the fields have been already updated
1666+ $ changed_fields = Submissions::getChangedFieldsSinceLastRender ($ form_id , $ view_id , $ submission_id , $ _POST ["tab " ], $ _POST );
1667+ Sessions::set ("new_search " , "yes " );
1668+ $ request ["view_id " ] = $ view_id ;
1669+ $ request ["editable_field_ids " ] = $ editable_field_ids ;
1670+
1671+ // if the DB had more up-to-date values, reset all the conflicting fields to save the last value in the DB before updating
1672+ // the database. We'll then present the conflicts to the user to choose whether to pick their new values or the existing
1673+ // ones
1674+ if (!empty ($ changed_fields )) {
1675+ foreach ($ changed_fields as $ field_name => $ value ) {
1676+ $ request [$ field_name ] = $ changed_fields [$ field_name ]["db_value " ];
1677+ }
1678+ }
1679+ list ($ success , $ message ) = Submissions::updateSubmission ($ form_id , $ submission_id , $ request );
1680+
1681+ if (!empty ($ changed_fields )) {
1682+ $ success = false ;
1683+ $ message = $ L ["notify_conflicts_detected " ];
1684+ }
1685+
1686+ // if there was any problem updating this submission, make a special note of it: we'll use that info to merge the
1687+ // current POST request info with the original field values to ensure the page contains the latest data (i.e. for
1688+ // cases where they fail server-side validation)
1689+ if (!$ success ) {
1690+ $ failed_validation = true ;
1691+ }
1692+ }
1693+
1694+ return array (
1695+ $ success ,
1696+ $ message ,
1697+ $ changed_fields ,
1698+ $ failed_validation
1699+ );
1700+ }
1701+
1702+
1703+ /**
1704+ * Used on the edit submission page to figure out what field are changed and return a list of DB + user values
1705+ * to present to the user.
1706+ * @param $grouped_fields
1707+ * @param $changed_fields
1708+ * @return array
1709+ */
1710+ public static function getChangedFieldsToReconcile ($ grouped_fields , $ changed_fields )
1711+ {
1712+ $ reconcile_changed_fields = array ();
1713+ $ user_values = array ();
1714+ foreach ($ changed_fields as $ changed_field_name => $ changed_info ) {
1715+ foreach ($ grouped_fields as $ group ) {
1716+ foreach ($ group ["fields " ] as $ field ) {
1717+ if ($ field ["field_name " ] !== $ changed_field_name ) {
1718+ continue ;
1719+ }
1720+
1721+ $ db_value = $ field ;
1722+ $ db_value ["is_editable " ] = "no " ;
1723+ $ db_value ["submission_value " ] = $ changed_info ["db_value " ];
1724+
1725+ $ user_value = $ field ;
1726+ $ user_value ["is_editable " ] = "no " ;
1727+ $ user_value ["submission_value " ] = $ changed_info ["user_value " ];
1728+
1729+ $ reconcile_changed_fields [] = array (
1730+ "field_name " => $ changed_field_name ,
1731+ "field_id " => $ field ["field_id " ],
1732+ "field_title " => $ field ["field_title " ],
1733+ "db_value " => $ db_value ,
1734+ "user_value " => $ user_value
1735+ );
1736+ $ user_values [$ changed_field_name ] = array (
1737+ "db_value " => $ changed_info ["db_value " ],
1738+ "user_value " => $ changed_info ["user_value " ]
1739+ );
1740+ }
1741+ }
1742+ }
1743+ Sessions::set ("conflicted_user_values " , $ user_values );
1744+
1745+ return $ reconcile_changed_fields ;
1746+ }
1747+
15971748 // -----------------------------------------------------------------------------------------------------------------
15981749
15991750
0 commit comments