Installation
composer require devigner/dynamics-crm-bundle
Add to config/bundles.php:
return [
// ...
Devigner\DynamicsCrmBundle\DevignerDynamicsCrmBundle::class => ['all' => true],
];
Configuration
Create config/packages/devigner_dynamics_crm.yaml:
devigner_dynamics_crm:
client_id: 'your_client_id'
client_secret: 'your_client_secret'
auth_url: 'https://login.microsoftonline.com/your_tenant_id/oauth2/token'
api_url: 'https://yourorg.crm.dynamics.com/api/data/v9.2/'
First Use Case: Fetching Accounts Inject the service in a controller:
use Devigner\DynamicsCrmBundle\Service\DynamicsCrmService;
class AccountController extends Controller
{
public function __construct(private DynamicsCrmService $crm)
{
}
public function index()
{
$accounts = $this->crm->getRecords('accounts');
return response()->json($accounts);
}
}
config/packages/devigner_dynamics_crm.yaml (configuration)src/Service/DynamicsCrmService.php (core service)src/DependencyInjection/ (bundle setup)// Create
$account = $this->crm->createRecord('accounts', [
'name' => 'Test Account',
'revenue' => 100000
]);
// Read
$account = $this->crm->getRecord('accounts', $accountId);
// Update
$this->crm->updateRecord('accounts', $accountId, ['name' => 'Updated Name']);
// Delete
$this->crm->deleteRecord('accounts', $accountId);
// Filter accounts by name
$accounts = $this->crm->getRecords('accounts', [
'$filter' => "name eq 'Test Account'"
]);
// Paging
$accounts = $this->crm->getRecords('accounts', [
'$top' => 10,
'$skip' => 20
]);
// Fetch contacts for an account
$contacts = $this->crm->getRelatedRecords('accounts', $accountId, 'contacts');
// Link a contact to an account
$this->crm->createRelationship('accounts', $accountId, 'contacts', $contactId);
$this->crm->bulkCreateRecords('accounts', [
['name' => 'Account 1'],
['name' => 'Account 2']
]);
ParameterBag or environment variables for sensitive credentials.DynamicsCrmException.config/packages/devigner_dynamics_crm.yaml for debugging:
devigner_dynamics_crm:
logging: true
Deprecated API Version
v9.2 by default. If your CRM instance uses a newer version, update api_url in config.v9.2/ → v10.0/).Authentication Failures
env() helper:
client_id: '%env(DYNAMICS_CRM_CLIENT_ID)%'
logging: true) and check var/log/dev.log.OData Query Limits
$top max 5000). Exceeding limits returns empty results.$skip/$top) for large datasets.Case Sensitivity in Filters
$filter are case-sensitive for unique identifiers (e.g., accountid). Use exact matches:
'$filter' => "accountid eq '00000000-0000-0000-0000-000000000000'"
Missing Response Handling
@odata.context). Validate responses:
try {
$data = $this->crm->getRecord('accounts', $id);
} catch (\Exception $e) {
if (strpos($e->getMessage(), 'Invalid entity') !== false) {
// Handle invalid entity
}
}
Use Entity Metadata Fetch entity metadata to discover available fields/relationships:
$metadata = $this->crm->getMetadata('accounts');
Leverage Webhooks (Advanced)
For real-time updates, use Dynamics CRM’s webhook system alongside this bundle. Store webhook secrets in Symfony’s security.yaml.
Testing
Mock DynamicsCrmService in PHPUnit:
$mock = $this->createMock(DynamicsCrmService::class);
$mock->method('getRecord')->willReturn(['name' => 'Test']);
$this->instance(DynamicsCrmService::class, $mock);
Performance
bulkCreateRecords).$select in queries):
$this->crm->getRecords('accounts', ['$select' => 'name,revenue']);
Extension Points
services.yaml:
services:
App\Service\CustomCrmService:
decorates: 'devigner_dynamics_crm.service.crm'
arguments: ['@devigner_dynamics_crm.service.crm']
How can I help you explore Laravel packages today?