Let the platform do the work

Duplicate Check

Overview

The duplicate-check framework provides the capability to alter how the system searches for duplicate records in the database when creating records. For information on duplicate checking during imports, please refer to the index documentation.

Default Strategy

The default duplicate-check strategy, located in ./data/duplicatecheck/FilterDuplicateCheck.php, is referred to as FilterDuplicateCheck. This strategy utilizes the Filter API and a defined filter in the vardefs of the module to search for duplicates and rank them based on matching data.

Custom Filter

To alter a defined filter for a stock a module, you only need to update the Vardefs using the Extensions framework. If you are working with a custom module, you can modify the vardefs in ./modules/<module>/vardefs.php directly. The FilterDuplicateCheck Strategy accepts two properties in its metadata:

Name Type Description
filter_template array An array containing the Filter Definition for which fields to search for duplicates on. Please consult the Filter API for further information on the filter syntax
ranking_fields array

A list of arrays with the following properties. The order in which you list the fields for ranking will determine the ranking score. The first ranks higher, than those after it.

in_field_name: Name of field in vardefs

dupe_field_name: Name of field returned by filter

Example

The following example will demonstrate how to manipulate the stock Accounts duplicate check to not filter on the shipping address city. The default Account duplicate_check defintion, located in ./modules/Accounts/vardefs.php, is shown below.

  ...
'duplicate_check' => array(
    'enabled' => true,
    'FilterDuplicateCheck' => array(
        'filter_template' => array(
            array(
                '$or' => array(
                    array('name' => array('$equals' => '$name')),
                    array('duns_num' => array('$equals' => '$duns_num')),
                    array(
                        '$and' => array(
                            array('name' => array('$starts' => '$name')),
                            array(
                                '$or' => array(
                                    array('billing_address_city' => array('$starts' => '$billing_address_city')),
                                    array('shipping_address_city' => array('$starts' => '$shipping_address_city')),
                                )
                            ),
                        )
                    ),
                )
            ),
        ),
        'ranking_fields' => array(
            array('in_field_name' => 'name', 'dupe_field_name' => 'name'),
            array('in_field_name' => 'billing_address_city', 'dupe_field_name' => 'billing_address_city'),
            array('in_field_name' => 'shipping_address_city', 'dupe_field_name' => 'shipping_address_city'),
        )
    )
),
...

 To add or remove fields from the check, you will need to manipulate $dictionary['<module>']['duplicate_check']['FilterDuplicateCheck']['filter_template'] and   $dictionary['<module>']['duplicate_check']['FilterDuplicateCheck']['ranking_fields'] . For our example, we will simply remove the references to shipping_address_city.  It is important to familiarize yourself with filter operators before making any changes.

./custom/Extension/modules/Accounts/Ext/Vardefs/newFilterDuplicateCheck.php

  <?php

$dictionary['Account']['duplicate_check']['FilterDuplicateCheck'] = array(
    'filter_template' => array(
        array(
            '$or' => array(
                array('name' => array('$equals' => '$name')),
                array('duns_num' => array('$equals' => '$duns_num')),
                array(
                    '$and' => array(
                        array('name' => array('$starts' => '$name')),
                        array(
                            '$or' => array(
                                array('billing_address_city' => array('$starts' => '$billing_address_city')),
                            )
                        ),
                    )
                ),
            )
        ),
    ),
    'ranking_fields' => array(
        array('in_field_name' => 'name', 'dupe_field_name' => 'name'),
        array('in_field_name' => 'billing_address_city', 'dupe_field_name' => 'billing_address_city'),
    )
);

Finally, navigate to Admin > Repair > Quick Repair and Rebuild. The system will then enable the custom duplicate-check class.

If you want to disable the duplicate check entirely, you can set $dictionary['<module>']['duplicate_check']['enabled'] to false in your vardefs and run a Quick Repair and Rebuild.

  $dictionary['Account']['duplicate_check']['enabled'] = false;

Custom Strategies

Custom duplicate-check class files are stored under ./custom/data/duplicatecheck/. The files in this directory can be enabled on a module's duplicate_check property located in ./custom/Extension/modules/<module>/Ext/Vardefs/. Only one duplicate-check class can be enabled on a module at a given time.

Duplicate Check Class

To create a custom duplicate-check strategy, you need to create a custom duplicate-check class that extends the base DuplicateCheckStrategy, ./data/duplicatecheck/DuplicateCheckStrategy.php. To work, this custom class requires the implementation of two methods:

Method Name Description
setMetadata Sets up properties for duplicate-check logic based on the passed-in metadata
findDuplicates Finds possible duplicate records for a given set of field data

Example

The following example will create a new duplicate-check class called "OneFieldDuplicateCheck" that will query the database based on the configured field for records that contain data similar to that one field:

./custom/data/duplicatecheck/OneFieldDuplicateCheck.php

  <?php

if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');

class OneFieldDuplicateCheck extends DuplicateCheckStrategy
{

    protected $field;

    public function setMetadata($metadata)
    {
        if (isset($metadata['field'])) {
            $this->field = $metadata['field'];
        }
    }

    public function findDuplicates()
    {
        if (empty($this->field)){
            return null;
        }

        $Query = new SugarQuery();
        $Query->from($this->bean);
        $Query->where()->ends($this->field,$this->bean->{$this->field});
        $Query->limit(10);
        //Filter out the same Bean during Edits
        if (!empty($this->bean->id)) { 
            $Query->where()->notEquals('id',$this->bean->id);
        }
        $results = $Query->execute();
        return array(
            'records' => $results
        );
    }
}

Vardef Settings

The duplicate-check vardef settings are configured on each module and can be altered using the Extension framework.

Name Type Description
enabled boolean Whether or not duplicate-check framework is enabled on the module
<class_name> array The class name that will provide duplicate checking, set to an array of metadata that gets passed to the duplicate-check class

 If you want to enable the OneFieldDuplicateCheck strategy (shown above) for the Accounts module, you must create the following file:

./custom/Extension/modules/Accounts/Ext/Vardefs/newDuplicateCheck.php

  <?php

$dictionary['Account']['duplicate_check'] = array(
	'enabled' => true,
	'OneFieldDuplicateCheck' => array(
            'field' => 'name'
        )
);

Finally, navigate to Admin > Repair > Quick Repair and Rebuild. The system will then enable the custom duplicate-check class.

Programmatic Usage

You can also use the duplicate-check framework in code such as in a logic hook or a scheduler. The following example shows how to use the module's defined duplicate-check strategy when utilizing a bean object by simply calling the findDuplicates method on the bean object:

  $account = BeanFactory::newBean('Accounts');
$account->name = 'Test';
$duplicates = $account->findDuplicates();

if (count($duplicates['records'])>0){
    $GLOBALS['log']->fatal("Duplicate records found for Account");
}