So here is my dilemma.
I have the contacts module I would like to use to handle client accounts. Then I have custom modules that I would like to sync the data across on every save.
For example, If I am in Contacts module and I save a record update. I will have all my child records updated.
When I update a child module, I would like the parent record to be updated.
The custom module I am using is based of the vanilla module for module builder. The plain non fancy do it yourself module.
After some digging around I found a great way of updating child records from here.
http://greg.ambrose.id.au/2013/11/03/assigning-child-records-in-sugarcrm/
That was a HUGE help in finding a method to automatically update my child records.
Next Since both modules will have the fields named the same I wanted to create a way to update each field with a foreach loop without having to type out every single field I want to sync. This was a way to create nice lean code.
In my efforts to do so I found my after_save hook crashing. After Much testing I found out my loop was also trying to sync fields you would not want to sync, for example ID.
So I created an array of fields I would like to exclude and ended with the below code.
I am providing this since I am sure someone else could use the help.
So here we go,
spoiler are keywords for people searching for my trouble
[spoiler]sugarcrm suitecrm sync modules sync custom modules sync fields between modules sync fields with custom module prevent loop after_save hook update child records[/spoiler]
<?php
/***********************************
Project: Pipe Sync
Original Dev: John Torres, April 2014
@2014 John Torres
john.torres87@outlook.com
Desc: Sync All Relevant fields through custom modules and contacts when specific conditions are met.
The contents of this file are governed by the GNU General Public License (GPL).
A copy of said license is available here: http://www.gnu.org/copyleft/gpl.html
This code is provided AS IS and WITHOUT WARRANTY OF ANY KIND.
*************************************/
//prevents directly accessing this file from a web browser
if(!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
class Reassign
{
// all the related modules we want to update
private $childModules = array(
'contacts_pipe_intake_1',
'documents',
'quotes'
);
//Array of fields to exclude for sync, such as db id's schema, all objects we do not want to work with!
private $excludefields = array (
status,
assigned_user_id,
assigned_user_name,
assigned_user_link,
id,
name,
date_entered,
date_modified,
modified_user_id,
modified_by_name,
created_by,
created_by_name,
description,
deleted,
created_by_link,
modified_user_link,
new_schema,
module_dir,
object_name,
table_name,
importable,
disable_row_level_security,
db,
new_with_id,
disable_vardefs,
new_assigned_user_name,
processed_dates_times,
process_save_dates,
save_from_post,
duplicates_found,
update_date_modified,
update_modified_by,
update_date_entered,
set_created_by,
team_set_id,
ungreedy_count,
module_name,
field_name_map,
field_defs,
custom_fields,
column_fields,
list_fields,
additional_column_fields,
relationship_fields,
current_notify_user,
fetched_row,
fetched_rel_row,
layout_def,
force_load_details,
optimistic_lock,
disable_custom_fields,
number_formatting_done,
process_field_encrypted,
acltype,
additional_meta_fields,
special_notification,
in_workflow,
tracker_visibility,
listview_inner_join,
in_import,
required_fields,
added_custom_field_defs,
acl_fields,
logicHookDepth,
contacts_pipe_intake_1,
contacts_pipe_intake_1_name,
contacts_pipe_intake_1contacts_ida,
relDepth,
contacts_pipe_intake_1_name_owner,
contacts_pipe_intake_1_name_owner_mod,
rel_fields_before_value
);
public function doReassign($bean, $event, $arguments)
{
// ok, we need to sync fields on all child records
// get the bean to load all its relationships
$links = $bean->get_linked_fields();
foreach($links as $relName => $rel)
{
//Comment out the below if-statement and uncomment the below error message
//check the log to see the relationship names available.
//$GLOBALS['log']->fatal($relName);
// ignore relationships we dont want
if(!in_array($relName, $this->childModules)) continue;
// lets load this related record
$ok = $bean->load_relationship($relName);
if($ok == false) trigger_error("Cant load rel $relName", E_USER_ERROR);
//get all the records for this relationship
$relBeans = $bean->$relName->getBeans();
//Work on each individual child record
foreach($relBeans as $relBean)
{
//sync all the fields
foreach($relBean as $relBeanField => $relBeanRest){
//exclude fields we do not want to sync, ex: $bean->id
if(in_array($relBeanField, $this->excludefields)) continue;
$relBean->$relBeanField=$bean->$relBeanField;
}
//let's save the current record
$relBean->save(false);
}
}
}
}
?>
Then on the chidl record on an after_save hook I will have an update parent record type of code.
The issue is this. When I trigger the save from lets say Module A this will trigger a save for Module B
When the Module B save is triggered, this will trigger a save for Module A and so on until boom.
I know I can just have some property get updated to prevent a loop for example as found here.
http://support.sugarcrm.com/02_Documentation/04_Sugar_Developer/Sugar_Developer_Guide_7.1/60_Logic_Hooks/90_Examples/Preventing_Infinite_Loops_with_Logic_Hooks/
But my issue is once there are concurrent updadtes to either module they will no longer update.
So this is for some of the experienced coders out there.
What logic can I use between the records to prevent a loop. But also allow concurrent future updadtes.
For example:
Update Module A updates child records for Module B, then Stop!
Update Module B child record updates parent record Module A then Stop!
Then when the same records update again allow for future syncs between records without a loop.
I just cant thing of any logic to do this, maybe I am simply tired.
A push in the right direction would be HUGE.
I was thinking of something like
Module A has variable $x
Module B has variable $y
When A is saved x= x+1
triggering a B save and y=y+1
if x=y then stop
But then what do i do for future updates to the record?
If I try lets say, when a save occurs, increase x+1
if x>y then :save
but that would cause a loop
I’m confused.
What would be a good solution to this?
I would like to accomplish this without having to resort to accessing the database with a query method.