{"id":37001201,"url":"https://github.com/wazzac/sync-model-to-crm","last_synced_at":"2026-01-14T00:08:41.818Z","repository":{"id":206775721,"uuid":"711414771","full_name":"wazzac/sync-model-to-crm","owner":"wazzac","description":"Laravel CRM Sync makes it effortless to connect and sync your Eloquent models with CRMs like HubSpot and PipeDrive. Define which model properties to sync, and let the package handle real-time, environment-aware synchronization across Sandbox, Production, and more.","archived":false,"fork":false,"pushed_at":"2025-08-05T06:53:11.000Z","size":270,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-27T16:44:37.361Z","etag":null,"topics":["crm","crm-integration","data-synchronization","eloquent","hubspot","laravel","laravel-12","laravel-crm","laravel-package","model-sync","model-to-crm","php","sync-to-crm"],"latest_commit_sha":null,"homepage":"https://wazzac.dev","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wazzac.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-10-29T07:32:20.000Z","updated_at":"2025-08-05T06:53:14.000Z","dependencies_parsed_at":"2023-11-19T10:23:01.237Z","dependency_job_id":"db04428b-adb3-4ab0-859b-ff4805f5c99f","html_url":"https://github.com/wazzac/sync-model-to-crm","commit_stats":null,"previous_names":["wazzac/sync-model-to-hubspot"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/wazzac/sync-model-to-crm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazzac%2Fsync-model-to-crm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazzac%2Fsync-model-to-crm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazzac%2Fsync-model-to-crm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazzac%2Fsync-model-to-crm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wazzac","download_url":"https://codeload.github.com/wazzac/sync-model-to-crm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazzac%2Fsync-model-to-crm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28406481,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T21:51:37.118Z","status":"ssl_error","status_checked_at":"2026-01-13T21:45:14.585Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crm","crm-integration","data-synchronization","eloquent","hubspot","laravel","laravel-12","laravel-crm","laravel-package","model-sync","model-to-crm","php","sync-to-crm"],"created_at":"2026-01-14T00:08:41.085Z","updated_at":"2026-01-14T00:08:41.805Z","avatar_url":"https://github.com/wazzac.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/wazzac/sync-model-to-crm/issues\"\u003e\u003cimg alt=\"GitHub issues\" src=\"https://img.shields.io/github/issues/wazzac/sync-model-to-crm\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/wazzac/sync-model-to-crm/stargazers\"\u003e\u003cimg alt=\"GitHub stars\" src=\"https://img.shields.io/github/stars/wazzac/sync-model-to-crm\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/wazzac/sync-model-to-crm/blob/main/LICENSE\"\u003e\u003cimg alt=\"GitHub license\" src=\"https://img.shields.io/github/license/wazzac/sync-model-to-crm\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/wazzac/sync-model-to-crm\"\u003e\u003cimg alt=\"GitHub version\" src=\"https://img.shields.io/github/v/tag/wazzac/sync-model-to-crm?label=version\u0026sort=semver\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Sync Model to CRM\n\nEasily synchronize your Laravel Eloquent models with remote CRM providers such as [HubSpot](https://www.hubspot.com/), [Pipedrive](https://www.pipedrive.com/en), and more. This package allows you to define which model properties and relationships should be kept in sync with external CRM objects, providing a seamless integration experience.\n\n---\n\n## Features\n\n-   **Flexible Property Mapping:** Define which model attributes map to CRM fields.\n-   **Multi-Environment Support:** Sync to multiple CRM environments (e.g., sandbox, production).\n-   **Relationship Sync:** Automatically associate related models (e.g., User to Company).\n-   **Customizable Sync Triggers:** Initiate syncs via observers, mutators, or queued jobs.\n-   **Extensible:** Easily add support for additional CRM providers.\n\n---\n\n## Supported CRMs\n\n-   **HubSpot**\n    -   Sync `User` model to HubSpot `Contact` object.\n    -   Sync `Entity` model to HubSpot `Company` object.\n    -   Manage associations between `Contact` and `Company`.\n    -   (Coming soon) Support for `Deal` and `Ticket` objects.\n-   **Planned Support**\n    -   Pipedrive\n    -   Salesforce\n    -   Zoho CRM\n    -   Others\n\n---\n\n## Requirements\n\n-   **PHP:** 8.2 or higher\n-   **Laravel:** 12.x\n\n---\n\n## How It Works\n\nDefine a set of properties on your Eloquent models to control how and when they sync with your CRM provider. After the first successful sync, the CRM object’s primary key is stored in a mapping table for efficient future updates.\n\n### Required Model Properties\n\nAdd the following properties to your model to enable CRM synchronization:\n\n| Property                       | Type              | Description                                                                                  |\n| ------------------------------ | ----------------- | -------------------------------------------------------------------------------------------- |\n| `$syncModelCrmEnvironment`     | string/array/null | CRM environments to sync with (e.g., `['sandbox', 'production']`). Defaults to config value. |\n| `$syncModelCrmPropertyMapping` | array (required)  | Maps local model attributes to CRM fields.                                                   |\n| `$syncModelCrmUniqueSearch`    | array (required)  | Defines unique fields for identifying CRM records.                                           |\n| `$syncModelCrmRelatedObject`   | string            | CRM object type (e.g., `contact`). Defaults to config mapping.                               |\n| `$syncModelCrmDeleteRules`     | array (required)  | Rules for handling deletes (soft/hard) in the CRM.                                           |\n| `$syncModelCrmActiveRules`     | array (required)  | Rules for restoring/reactivating records in the CRM.                                         |\n| `$syncModelCrmAssociateRules`  | array (optional)  | Defines associations with other CRM objects.                                                 |\n\n---\n\n### Example: User Model\n\nBelow is a sample `User` model configured for CRM synchronization:\n\n```php\nnamespace App\\Models;\n\n// use Illuminate\\Contracts\\Auth\\MustVerifyEmail;\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Laravel\\Sanctum\\HasApiTokens;\nuse App\\Models\\Entity;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Wazza\\SyncModelToCrm\\Http\\Controllers\\CrmProviders\\HubSpotController;\nuse Wazza\\SyncModelToCrm\\Traits\\HasCrmSync;\n\nclass User extends Authenticatable\n{\n    use HasApiTokens, HasFactory, Notifiable, SoftDeletes;\n\n    // include this if you wish to use the `Mutators function` or\n    // $this-\u003esyncToCrm() directly as appose to the observer method\n    use HasCrmSync;\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\u003cint, string\u003e\n     */\n    protected $fillable = [\n        'name',\n        'email',\n        'password',\n    ];\n\n    /**\n     * The attributes that should be hidden for serialization.\n     *\n     * @var array\u003cint, string\u003e\n     */\n    protected $hidden = [\n        'password',\n        'remember_token',\n    ];\n\n    /**\n     * The attributes that should be cast.\n     *\n     * @var array\u003cstring, string\u003e\n     */\n    protected $casts = [\n        'email_verified_at' =\u003e 'datetime',\n        'password' =\u003e 'hashed',\n    ];\n\n    /**\n     * Function that will be used to return the relationship data\n     * @return type\n     */\n    public function entity()\n    {\n        return $this-\u003ebelongsTo(Entity::class)-\u003ewithTrashed();\n    }\n\n    // --------------------------------------------------------------\n    // Sync Model to CRM\n    // --------------------------------------------------------------\n\n    /**\n     * The CRM provider environment/s to use (e.g. production, sandbox, etc.)\n     * Use an array to sync to multiple environments.\n     * `null` (or not defined) will take the default from the config file.\n     *\n     * @var string|array|null\n     */\n    public $syncModelCrmEnvironment = ['sandbox']; // ..or ['sandbox','production']\n\n    /**\n     * Mapping array for local and CRM properties\n     * This will be the primary property used to cycle through the crm providers\n     * and properties to sync the model to the CRM.\n     * Required - if not provided, the sync will process will be skipped (no Exceptions will be thrown)\n     *\n     * @var array\n     */\n    public $syncModelCrmPropertyMapping = [\n        'hubspot' =\u003e [\n            'name' =\u003e 'firstname',\n            'email' =\u003e 'email',\n            // ... add all the properties that you would like to sync\n        ],\n    ];\n\n    /**\n     * Unique filters for the CRM to locate the record if there is no internal mapping available.\n     * Not required, but strongly encouraged to be configured as to avoid any duplicate record creation in the crm\n     *\n     * @var array\n     */\n    public $syncModelCrmUniqueSearch = [\n        'hubspot' =\u003e [\n            'email' =\u003e 'email', // this will ensure that the search filter is unique\n        ],\n    ];\n\n    /**\n     * The CRM object to sync this model to.\n     * This is the CRM object type (e.g. contact, company, deal, etc.)\n     * If this is null or not provided, the `object_table_mapping` key will be used from the config file.\n     *\n     * @var string\n     */\n    public $syncModelCrmRelatedObject = 'contact';\n\n    /**\n     * The CRM Delete rules to follow.\n     * i.e. if Soft-delete is applicable, what should the CRM record be updated to?\n     * if Hard-delete is used, the record will be deleted/archived in the CRM.\n     *\n     * @var array\n     */\n    public $syncModelCrmDeleteRules = [\n        'hard_delete' =\u003e [\n            'hubspot' =\u003e false,\n        ],\n        'soft_delete' =\u003e [\n            'hubspot' =\u003e [\n                'lifecyclestage' =\u003e 'other',\n                'hs_lead_status' =\u003e 'DELETED',\n            ],\n        ]\n    ];\n\n    /**\n     * The CRM Active/Restore rules to follow.\n     * These will be the rules to follow for any new entries that are not soft-deleted.\n     *\n     * @var array\n     */\n    public $syncModelCrmActiveRules = [\n        'hubspot' =\u003e [\n            'lifecyclestage' =\u003e 'customer',\n            'hs_lead_status' =\u003e 'OPEN',\n        ],\n    ];\n\n    /**\n     * The CRM Associations to sync.\n     * This is used to associate the model with other CRM objects.\n     *\n     * @var array\n     */\n    public $syncModelCrmAssociateRules = [\n        [\n            'assocMethod'   =\u003e 'entity', // App\\Models\\Entity::class\n            'provider' =\u003e [\n                'hubspot' =\u003e [\n                    [\n                        'association_category' =\u003e HubSpotController::ASSOCIATION_CATEGORY__HUBSPOT_DEFINED,\n                        'association_type_id' =\u003e HubSpotController::ASSOCIATION_TYPE_ID__CONTACT_TO_COMPANY_PRIMARY,\n                    ],\n                    [\n                        'association_category' =\u003e HubSpotController::ASSOCIATION_CATEGORY__HUBSPOT_DEFINED,\n                        'association_type_id' =\u003e HubSpotController::ASSOCIATION_TYPE_ID__CONTACT_TO_COMPANY,\n                    ],\n                ],\n            ],\n        ],\n    ];\n\n    // --------------------------------------------------------------\n    // Custom Methods to initiate a sync\n    // --------------------------------------------------------------\n\n    /**\n     * (1) Register the observer in the AppServiceProvider boot method\n     *\n     * public function boot(): void\n     *  {\n     *      // register the observer/s\n     *      // ...refer the the template examples in the sync-model-to-crm repo for a observer working copy\n     *      \\App\\Models\\User::observe(\\App\\Observers\\UserObserver::class);\n     *  }\n     */\n\n\n    /**\n     * (2) Mutators function (Laravel 5.4 or above)\n     *\n     * Laravel provides mutators which are methods that can be defined on a model to modify\n     * attributes before they are saved. You can create a custom mutator named save that\n     * first calls the original save method using parent::save() and then performs your\n     * additional action.\n     *\n     * @param array $options\n     * @return void\n     */\n    public function save(array $options = [])\n    {\n        parent::save($options);\n\n        // lets call the syncModelToCrm method to sync the model to the CRM.\n        // refer to the trait for all the available methods\n        $this-\u003esyncToCrmPatch(); // -- disabled as we are currently using the observer method\n    }\n}\n```\n\n---\n\n## Usage\n\nYou can trigger a model sync in several ways:\n\n1. **Using the ShouldSyncToCrmOnSave (Automatic Sync on Save):**\n   Add the `ShouldSyncToCrmOnSave` to your Eloquent model to automatically trigger a CRM sync every time the model is saved (created or updated). This is the easiest way to ensure your model stays in sync with your CRM provider without writing custom logic.\n\n    ```php\n    use Wazza\\SyncModelToCrm\\Traits\\ShouldSyncToCrmOnSave;\n\n    class User extends Authenticatable\n    {\n        use ShouldSyncToCrmOnSave;\n        // ...\n    }\n    ```\n\n    **When to use:**\n    - Use `ShouldSyncToCrmOnSave` if you want your model to always sync to the CRM automatically after every save (create/update), with no extra code required.\n    - This is ideal for most use cases where you want seamless, automatic syncing.\n\n2. **Using the HasCrmSync (Manual or Custom Sync):**\n   Add the `HasCrmSync` to your model if you want to control exactly when the sync happens. This trait provides methods like `$this-\u003esyncToCrm()`, `$this-\u003esyncToCrmCreate()`, `$this-\u003esyncToCrmUpdate()`, etc., which you can call from mutators, custom methods, or anywhere in your application.\n\n    ```php\n    use Wazza\\SyncModelToCrm\\Traits\\HasCrmSync;\n\n    class User extends Authenticatable\n    {\n        use HasCrmSync;\n        // ...\n    }\n\n    public function save(array $options = [])\n    {\n        parent::save($options);\n        $this-\u003esyncToCrmPatch(); // Manually trigger sync after save\n    }\n    ```\n\n    **When to use:**\n    - Use `HasCrmSync` if you want to trigger syncs only at specific times, or if you need to customize the sync logic (e.g., only sync on certain conditions, or from a controller, observer, or job).\n    - This is ideal for advanced use cases or when you want more granular control over syncing.\n\n3. **Directly in a Controller:**\n\n    ```php\n    // If CrmSyncController is registered as a singleton in the service container,\n    // you should resolve it via dependency injection or the app() helper\n    // to ensure you get the singleton instance:\n    app(CrmSyncController::class)-\u003esetModel($user)-\u003eexecute();\n\n    // Or, if you're inside a controller or method with dependency injection:\n    public function syncUser(CrmSyncController $crmController, User $user)\n    {\n        $crmController-\u003esetModel($user)-\u003eexecute();\n    }\n    ```\n\n    **Note:**\n    Instantiating with `new CrmSyncController()` will always create a new instance, bypassing the singleton.\n    To use the singleton, always resolve it from the container.\n\n4. **Via an Observer:**\n   Register an observer to automatically sync after save, update, delete, or restore events.\n\n5. **In a Job:**\n   Offload sync logic to a queued job for asynchronous processing.\n\n---\n\n## Installation\n\n1. **Install via Composer:**\n\n    ```bash\n    composer require wazza/sync-model-to-crm\n    ```\n\n2. **Register the Service Provider (if not auto-discovered):**\n   Add to `bootstrap/providers.php`:\n\n    ```php\n    return [\n            App\\Providers\\AppServiceProvider::class,\n            Wazza\\SyncModelToCrm\\Providers\\SyncModelToCrmServiceProvider::class,\n    ];\n    ```\n\n    \u003e _If your package supports Laravel auto-discovery, this step may be optional._\n\n3. **Publish Config and Migrations:**\n\n    ```bash\n    php artisan vendor:publish --tag=\"sync-modeltocrm-config\"\n    php artisan vendor:publish --tag=\"sync-modeltocrm-migrations\"\n    php artisan migrate\n    ```\n\n4. **Configure Environment Variables:**\n   Add the following to your `.env` file (see `config/sync_modeltocrm.php` for details):\n\n    ```\n    SYNC_MODEL_TO_CRM_DB_PRIMARY_KEY_FORMAT=int\n    SYNC_MODEL_TO_CRM_HASH_SALT=Ey4cw2BHvi0HmGYjyqYr\n    SYNC_MODEL_TO_CRM_HASH_ALGO=sha256\n    SYNC_MODEL_TO_CRM_LOG_INDICATOR=sync-modeltocrm\n    SYNC_MODEL_TO_CRM_LOG_LEVEL=3\n    SYNC_MODEL_TO_CRM_PROVIDER=hubspot\n    SYNC_MODEL_TO_CRM_ENVIRONMENT=sandbox\n    SYNC_MODEL_TO_CRM_PROVIDER_HUBSPOT_SANDBOX_URI=https://api.hubapi.com/crm/v4/\n    SYNC_MODEL_TO_CRM_PROVIDER_HUBSPOT_SANDBOX_TOKEN=xxx-xxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n    ```\n\n5. **Cache Config:**\n\n    ```bash\n    php artisan config:clear\n    php artisan config:cache\n    ```\n\n6. **Review Configuration:**\n   Adjust the published config file as needed. You also do not need all of the env settings above, have a look at the config file\n   and overwrite any applicable items. Happy coding 😉\n\n---\n\n## Monitoring \u0026 Logs\n\nSet your desired log level in the config file (`1` = high, `3` = low verbosity).\nMonitor sync activity in your Laravel log file:\n\n```bash\ntail -f storage/logs/laravel.log | grep sync-modeltocrm\n```\n\n---\n\n## Testing\n\nWe have included a few unit tests, please expand if you wish to fork and help expand the functionalities.\n\n```bash\n./vendor/bin/pest\n```\n\nExample output:\n\n```bash\n     PASS  Tests\\Unit\\EnvTest\n    ✓ it should have the correct environment variables set         1.11s\n\n     PASS  Tests\\Unit\\ExampleTest\n    ✓ it contains a successful example unit test                   0.33s\n\n     PASS  Tests\\Unit\\ModelTest\n    ✓ it can create a new SmtcExternalKeyLookup model record       0.31s\n    ✓ it can mass assign data to the SmtcExternalKeyLookup model   0.25s\n    ✓ it can update the SmtcExternalKeyLookup model record         0.35s\n\n     PASS  Tests\\Feature\\ExampleTest\n    ✓ it contains a successful example feature test                0.24s\n\n    Tests:    6 passed (25 assertions)\n    Duration: 3.84s\n```\n\n\u003e More tests and features coming soon!\n\n---\n\n## License\n\nThis project is open-sourced under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwazzac%2Fsync-model-to-crm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwazzac%2Fsync-model-to-crm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwazzac%2Fsync-model-to-crm/lists"}