{"id":28509403,"url":"https://github.com/justbetter/laravel-dynamics-client","last_synced_at":"2026-04-01T18:31:22.916Z","repository":{"id":49981183,"uuid":"518484973","full_name":"justbetter/laravel-dynamics-client","owner":"justbetter","description":"A package to easily use Microsoft Dynamics web services via OData with Laravel","archived":false,"fork":false,"pushed_at":"2026-03-19T07:39:53.000Z","size":415,"stargazers_count":41,"open_issues_count":0,"forks_count":11,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-03-20T00:48:56.525Z","etag":null,"topics":["client","dynamics","laravel","php"],"latest_commit_sha":null,"homepage":"","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/justbetter.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-07-27T14:10:01.000Z","updated_at":"2026-03-19T07:39:57.000Z","dependencies_parsed_at":"2025-01-24T14:29:54.004Z","dependency_job_id":"278ee619-fd72-4a61-961a-873320b74916","html_url":"https://github.com/justbetter/laravel-dynamics-client","commit_stats":{"total_commits":30,"total_committers":4,"mean_commits":7.5,"dds":"0.30000000000000004","last_synced_commit":"1ba655d335873d2314eec4f1649ea5ba915db920"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/justbetter/laravel-dynamics-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justbetter%2Flaravel-dynamics-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justbetter%2Flaravel-dynamics-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justbetter%2Flaravel-dynamics-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justbetter%2Flaravel-dynamics-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/justbetter","download_url":"https://codeload.github.com/justbetter/laravel-dynamics-client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justbetter%2Flaravel-dynamics-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290872,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: 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":["client","dynamics","laravel","php"],"created_at":"2025-06-08T22:08:25.664Z","updated_at":"2026-04-01T18:31:22.896Z","avatar_url":"https://github.com/justbetter.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://github.com/justbetter/laravel-dynamics-client\" title=\"JustBetter\"\u003e\n    \u003cimg src=\"./art/banner.svg\" alt=\"Package banner\"\u003e\n\u003c/a\u003e\n\n# Laravel Dynamics Client\n\nThis package will connect you to your Microsoft Dynamics web services via OData. Custom web services can easily be\nimplemented and mapped to your liking. It uses the [HTTP client](https://laravel.com/docs/master/http-client) of Laravel\nwhich means that you can easily fake requests when writing tests.\n\nThe way we interact with OData has been inspired by Laravel's Query Builder.\n\n```php\n$customer = Customer::query()-\u003efindOrFail('1000');\n\n$customer-\u003eupdate([\n    'Name' =\u003e 'John Doe',\n]);\n\n$customers = Customer::query()\n    -\u003ewhere('City', '=', 'Alkmaar')\n    -\u003elazy();\n\n$items = Item::query()\n    -\u003ewhereIn('No', ['1000', '2000'])\n    -\u003eget();\n\n$customer = Customer::new()-\u003ecreate([\n    'Name' =\u003e 'Jane Doe',\n]);\n```\n\n## Installation\n\nInstall the composer package.\n\n```shell\ncomposer require justbetter/laravel-dynamics-client\n```\n\n## Setup\n\nPublish the configuration of the package.\n\n```shell\nphp artisan vendor:publish --provider=\"JustBetter\\DynamicsClient\\ServiceProvider\" --tag=config\n```\n\n## Configuration\n\nAdd your Dynamics credentials in the `.env`:\n\n```\nDYNAMICS_BASE_URL=https://127.0.0.1:7048/DYNAMICS\nDYNAMICS_VERSION=ODataV4\nDYNAMICS_COMPANY=\nDYNAMICS_USERNAME=\nDYNAMICS_PASSWORD=\nDYNAMICS_PAGE_SIZE=1000\n```\n\nBe sure the `DYNAMICS_PAGE_SIZE` is set equally to the `Max Page Size` under `OData Services` in the configuration of\nDynamics. This is crucial for the functionalities of the `lazy` method of the `QueryBuilder`.\n\n### Authentication\n\n\u003e **Note:** Be sure that Dynamics has been properly configured for OData.\n\nThis package uses NTLM authentication by default. If you are required to use basic auth or OAuth you can change this in\nyour `.env`.\n\n```\nDYNAMICS_AUTH=basic\n```\n\n#### OAuth\n\nTo setup OAuth add the following to your `.env`\n\n```dotenv\nDYNAMICS_AUTH=oauth\nDYNAMICS_OAUTH_CLIENT_ID=\nDYNAMICS_OAUTH_CLIENT_SECRET=\nDYNAMICS_OAUTH_REDIRECT_URI=\nDYNAMICS_OAUTH_SCOPE=\n```\n\nWhen using D365 cloud with [Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow) your redirect uri will be: `https://login.microsoftonline.com/\u003ctenant\u003e/oauth2/v2.0/token`\nand your base url should be `https://api.businesscentral.dynamics.com/v2.0/\u003ctenant\u003e/\u003cenvironment\u003e`.\n\n### Connections\n\nMultiple connections are supported. You can easily update your `dynamics` configuration to add as many connections as\nyou wish.\n\n```php\n// Will use the default connection.\nCustomer::query()-\u003efirst();\n\n// Uses the supplied connection.\nCustomer::query('other_connection')-\u003efirst();\n```\n\nBy default, the client will use the `company` field to select the Dynamics company.\nIf you wish to use the company's UUID you can simply add an `uuid` field:\n\n```php\n        'Company' =\u003e [\n            'base_url' =\u003e env('DYNAMICS_BASE_URL'),\n            'version' =\u003e env('DYNAMICS_VERSION', 'ODataV4'),\n            'company' =\u003e 'Company Name',\n            'uuid' =\u003e 'Company UUID', // The UUID will be prioritized over the company name\n```\n\n## Adding web services\n\nAdding a web service to your configuration is easily done. Start by creating your own resource class to map te data to.\n\n```php\nuse JustBetter\\DynamicsClient\\OData\\BaseResource;\n\nclass Customer extends BaseResource\n{\n    //\n}\n```\n\n### Primary Key\n\nBy default, the primary key of a resource will default to `No` as a string. You can override this by supplying the\nvariable `$primaryKey`.\n\n```php\npublic array $primaryKey = [\n    'Code',\n];\n```\n\n### Data Casting\n\nFields in resources will by default be treated as a string. For some fields, like a line number, this should be casted\nto an integer.\n\n```php\npublic array $casts = [\n    'Line_No' =\u003e 'int',\n];\n```\n\n### Registering Your Resource\n\nLastly, you should register your resource in your configuration file to let the package know where the web service is\nlocated. This should correspond to the service name configured in Dynamics.\n\nIf your resource class name is the same as the service name, no manual configuration is needed.\n\n\u003e **Note:** Make sure your web service is published.\n\n```php\nreturn [\n\n    /* Resource Configuration */\n    'resources' =\u003e [\n        Customer::class =\u003e 'CustomerCard',\n    ],\n\n];\n```\n\n## Query Builder\n\nQuerying data is easily done using the QueryBuilder.\n\nUsing the `get` method will only return the first result page. If you wish to efficiently loop through all records,\nuse `lazy` instead.\n\n```php\n$customers = Customer::query()\n    -\u003ewhere('City', '=', 'Alkmaar')\n    -\u003elazy()\n    -\u003eeach(function(Customer $customer): void {\n        //\n    });\n```\n\nSee the `QueryBuilder` class for all available methods.\n\n## Relations\n\nAny relations published on a page can be accessed as well using the resource.\n\n```php\n$salesOrder = SalesOrder::query()-\u003efirst();\n\n// Get the lines via the \"relation\" method.\n$salesLines = $salesOrder-\u003erelation('Relation_Name', SalesLine::class)-\u003eget();\n\n// Or use the \"lines\" helper on the SalesOrder.\n$salesLines = $salesOrder-\u003elines('Relation_Name')-\u003eget();\n```\n\nNote that the `relation` method itself returns an instance of a query builder. This means that you can add additional where-clauses like you would be able to on a regular resource.\n\n## Creating records\n\nCreate a new record.\n\n```php\nCustomer::new()-\u003ecreate([\n    'Name' =\u003e 'John Doe'\n])\n```\n\n## Updating records\n\nUpdate an existing record.\n\n```php\n$customer = Customer::query()-\u003efind('1000');\n$customer-\u003eupdate([\n    'Name' =\u003e 'John Doe',\n]);\n```\n\n## Deleting records\n\nDelete a record.\n\n```php\n$customer = Customer::query()-\u003efind('1000');\n$customer-\u003edelete();\n```\n\n## Debugging\n\nIf you wish to review your query before you sent it, you may want to use the `dd` function on the builder.\n\n```php\nCustomer::query()\n    -\u003ewhere('City', '=', 'Alkmaar')\n    -\u003ewhereIn('No', ['1000', '2000'])\n    -\u003edd();\n\n// Customer?$filter=City eq 'Alkmaar' and (No eq '1000' or No eq '2000')\n```\n\n## Commands\n\nYou can run the following command to check if you can successfully connect to Dynamics.\n\n```shell\nphp artisan dynamics:connect {connection?}\n```\n\n## Extending\n\nIf needed, it is possible to extend the provided `ClientFactory` class by creating your own. You **must** implement the `ClientFactoryContract` interface and its methods.\n\n\n```php\nuse JustBetter\\DynamicsClient\\Exceptions\\DynamicsException;\nuse JustBetter\\DynamicsClient\\Contracts\\ClientFactoryContract;\n\nclass MyCustomClientFactory implements ClientFactoryContract\n{\n    public function __construct(public string $connection)\n    {\n        $config = config('dynamics.connections.'.$connection);\n\n        if (! $config) {\n            throw new DynamicsException(\n                __('Connection \":connection\" does not exist', ['connection' =\u003e $connection])\n            );\n        }\n\n        $this\n            -\u003eheader('Authorization', 'Bearer ' . $config['access_token'])\n            -\u003eheader('Accept', 'application/json')\n            -\u003eheader('Content-Type', 'application/json');\n    }\n\n    ...\n}\n```\n\nYou will then need to bind your custom factory as the implementation of the contract, in any of your `ServiceProvider` register method :\n\n```php\n\u003c?php\n\nuse JustBetter\\DynamicsClient\\Contracts\\ClientFactoryContract;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this-\u003eapp-\u003ebind(ClientFactoryContract::class, MyCustomClientFactory::class);\n    }\n}\n```\n\n## Fake requests to Dynamics\n\nWhen writing tests you may find yourself in the need of faking a request to Dynamics. Luckily, this packages uses the\nHTTP client of Laravel to make this very easy.\n\nIn order to fake all requests to Dynamics, you can call the method `fake` on any resource.\n\n\u003e The `fake` method will fake **all** requests to Dynamics, not just the endpoint of the used resource.\n\n```php\n\u003c?php\n\nuse JustBetter\\DynamicsClient\\OData\\BaseResource;\n\nBaseResource::fake();\n```\n\nThis method will fake the Dynamics configuration and removes sensitive information like usernames and passwords. Only\nthe company name will remain in order to easily test with multiple connections.\n\n```php\n\u003c?php\n\nuse Illuminate\\Support\\Facades\\Http;\nuse JustBetter\\DynamicsClient\\OData\\Pages\\Item;\n\nItem::fake();\n\nHttp::fake([\n    'dynamics/ODataV4/Company(\\'default\\')/Item?$top=1' =\u003e Http::response([\n        'value' =\u003e [\n            [\n                '@odata.etag' =\u003e '::etag::',\n                'No' =\u003e '::no::',\n                'Description' =\u003e '::description::',\n            ],\n        ],\n    ]),\n]);\n\n$item = Item::query()-\u003efirst();\n```\n\n## Availability\n\nThis client can prevent requests from going to Dynamics when it is giving HTTP status codes 503, 504 or timeouts. This can be configured per connection in the `availability` settings. Enable the `throw` option to prevent any requests from going to Dynamics.\n\n## Contributing\n\nPlease see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.\n\n## Security Vulnerabilities\n\nPlease review [our security policy](../../security/policy) on how to report security vulnerabilities.\n\n## Credits\n\n- [Vincent Boon](https://github.com/VincentBean)\n- [Ramon Rietdijk](https://github.com/ramonrietdijk)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n\n\u003ca href=\"https://justbetter.nl\" title=\"JustBetter\"\u003e\n    \u003cimg src=\"./art/footer.svg\" alt=\"Package footer\"\u003e\n\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustbetter%2Flaravel-dynamics-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjustbetter%2Flaravel-dynamics-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustbetter%2Flaravel-dynamics-client/lists"}