PHPackages                             coolrunner/business-central-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. coolrunner/business-central-sdk

ActiveLibrary

coolrunner/business-central-sdk
===============================

PHP SDK for Microsoft Business Central

2.0.0(2y ago)1427.6k↓17.9%17[10 issues](https://github.com/CoolRunner-dk/business-central-php/issues)[2 PRs](https://github.com/CoolRunner-dk/business-central-php/pulls)MITPHPPHP ^8.1

Since May 12Pushed 2y ago3 watchersCompare

[ Source](https://github.com/CoolRunner-dk/business-central-php)[ Packagist](https://packagist.org/packages/coolrunner/business-central-sdk)[ RSS](/packages/coolrunner-business-central-sdk/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (5)Versions (38)Used By (0)

Business Central for PHP
========================

[](#business-central-for-php)

License: MIT
This software is provided as is and without any warrenties of any kind.
If you find a bug or have a feature request, please create an [issue](https://github.com/CoolRunner-dk/business-central-php/issues)

Install using Composer
----------------------

[](#install-using-composer)

`composer require coolrunner/business-central-sdk`

#### Getting Started

[](#getting-started)

- [Register](https://dynamics.microsoft.com/en-us/business-central/overview/) for a set of Business Central credentials
    - The SDK uses Basic Authentication
- Install the library into your application
- Load the SDK

#### Building Models

[](#building-models)

As Business Central's web services are dynamically created all entities could be pre generated.

```
BusinessCentral\Constructor::buildModels(
    'my-tenant-id.onmicrosoft.com',
    'Application (client) ID',
    'CLIENT_SECRET'
);
```

This can be generated using a `post-autoload-dump` composer script using your credentials to get the entities exposed through your web services.

#### Connecting to Business Central

[](#connecting-to-business-central)

Business Central for PHP uses a singleton pattern for SDK instances.

Once an instance has been initialized it will fetch the schema from your Business Central. (Standard entities are included).

```
$sdk = \BusinessCentral\SDK::instance('my-tenant-id.onmicrosoft.com', [
	// OAuth2 [Required]
    'client_id' => 'Application (client) ID',

    // Basic auth token [Required]
    'client_secret'    => '***',

    // Default collection size [Optional]
    // Amount of entities to load initially and per page per collection
    // Can be changed on the fly on any collection instance
    'default_collection_size' => 20,

    // Default environment [Optional - 'production' by default]
    'environment' => 'dev'
]);
```

#### Fetching Entities Manually

[](#fetching-entities-manually)

Business Central for PHP uses an internal query builder to navigate and fetch entities.

##### Accessing the query

[](#accessing-the-query)

```
$query = $sdk->query();
```

##### Navigating using the query

[](#navigating-using-the-query)

```
$query = $sdk->query();

// Navigate using ->navigateTo(...) (or shorthand ->to(...))
$query->to('Company','CompanyName')->to('invoicingCustomers'); // Equivalent of fetching from 'Company(CompanyName)/invoicingCustomers'
```

##### Fetching results

[](#fetching-results)

```
$collection = $query->fetch(); // Fetches the results of the query as a collection

// Fetches the first result of the query
$entity = $query->first(); // equivalent of $query->fetch()->first()

// Fetches all the results of the query
$entity = $query->all(); // Fetches all matching entities
```

#### Fetching Entities

[](#fetching-entities)

```
// Fetch a single company
$company = $sdk->company('CompanyName');
// Fetch all companies available to the authorized user
$companies = $sdk->companies();
```

Class Reference
---------------

[](#class-reference)

### Entity

[](#entity)

Class for Entity fetched from Business Central

#### Entity Properties / Relations

[](#entity-properties--relations)

Due to the dynamics of Business Central, the Entities from Business Central doesn't necessary have standardized properties across all implementations. Please refer to your specific implementation.

Alternatively check the entities.md generated when building models.

##### Fetch Relation

[](#fetch-relation)

You can fetch relations from a given entity by calling the name of the relation as a property or method:

```
// Returns a collection of entities if the relation is a collection,
// else returns the single instance of the related entity or if none is found
$customers = $entity->relation;
// Returns a query builder pointing at the relation - Use this if you have further filters (See [Builer/Filters](#builderfilters))
$customers = $entity->relation();
```

If the relations isn't pointing at a collection, then only the single related entity will be returned.

Check [Entities Overview](entities.md) to see if the relation is a collection type or not.

#### Entity Methods

[](#entity-methods)

- `fill(array $attributes)` : [Entity](#entity)

    - Update/set multiple properties as once - Only fillable properties will be set
    - Check the individual entity type on [Entities Overview](entities.md)
- `save()` : `bool`

    - Save the entity to Business Central
- `validate()` : `bool`

    - Validate the entity against the rules set by Business Central (this method is also called during `save()`
- `getEntityType`: [EntityType](#entitytype)

    - Get the entity's EntityType
- `query()` : [Builder](#builder)

    - Get a query pointing to the entity
- `toArray()` : `array`

    - Get the entity as an associative array

### EntityCollection

[](#entitycollection)

Container class for Entities fetched from Business Central

#### EntityCollection Properties

[](#entitycollection-properties)

None

#### EntityCollection Methods

[](#entitycollection-methods)

- `find(string|array $id, $default = null)` : [Entity](#entity) | `null`

    - Finds and returns an entity from the collection with the given id or `$default` on failure
- `create(array $attributes)` : [Entity](#entity)

    - Creates and returns a new Entity with the given attributes
- `update(string|array  $id, array $attributes)` : [Entity](#entity)

    - Updates and returns an existing Entity with the given attributes
- `delete(string|array  $id)` : `bool`

    - Deletes en entity from the collection with the given id - Returns true/false on success/failure
- `first($default = null)` : [Entity](#entity) | `null` | `mixed`

    - Returns the first index of the collection or `$default` is empty
- `count()` : `int`

    - Returns the amount of entities in the collection
- `all()` : `array`

    - Get all Entities in the collection as an array
    - This is a heavy method call on large collections - Use wisely!
    - Note: If the EntityCollection isn't fully loaded then the remaining Entities will be fetched!
- `getEntitySet`: [EntitySet](#entityset)

    - Get the collections EntitySet
- `query()` : [Builder](#builder)

    - Get a query pointing to the collection (includes extentions)
- `toArray()` : `array`

    - Get the collection as an array (converts all entities within also)

### Builder

[](#builder)

Query builder used to fetch and update entities on Business Central

Note: All EntityCollection method calls can be performed on the Builder instance itself,
due to an internal call to `$collection->fetch()` before the method call.

#### Builder Properties

[](#builder-properties)

None

#### Builder Methods

[](#builder-methods)

##### Builder Navigation

[](#builder-navigation)

- `navigateTo(string $component, string $id = null) | to(string $component, string $id = null)` : `self`

    - Point the Builder towards a component
- `fetch()` : [EntityCollection](#entitycollection)

    - Fetch all entities at the pointer

##### Builder Meta

[](#builder-meta)

- `count()` : `int`

    - Get the total count matching the Builder
- `exists()` : `bool`

    - Check if anything matches the builder

##### Builder Pagination

[](#builder-pagination)

- `limit(int $limit = null)` : `self`|`int`

    - Set the limit if `$limit` is set, else returns the current limit
- `page(int $page = null)` : `self`|`int`

    - Set the page if `$page` is set, else returns the current page
- `nextPage()` : `self`

    - Flip to the next page
- `prevPage()` : `self`

    - Flip to the previous page

##### Builder Sorting

[](#builder-sorting)

- `orderBy($property, string $direction = 'asc')` : `self`

    - Sort the Builder by a specified property and $direction
    - The `$field` property can be an array containing multiple conditions ( \['property' =&gt; 'direction'\] )
- `orderByAsc(string $property)` : `self`

    - Sort the Builder by a specified property ascending
- `orderByDesc(string $property)` : `self`

    - Sort the Builder by a specified property descending

##### Builder Expansion

[](#builder-expansion)

OData Reference: [Reference](http://docs.oasis-open.org/odata/odata/v4.0/cs01/part1-protocol/odata-v4.0-cs01-part1-protocol.html#_System_Query_Option_6)

- `expand(array $relations)` : `self`
    - Expand selection Expansion allows us to fetch multiple levels of entities in a single request.
        This allows us to minimize the amount of requests needed to get the entities needed.

###### Basic Usage

[](#basic-usage)

Example:

```
$company->customers()->expand([
    'paymentMethod',
    'picture',
])->fetch();
```

The above will fetch a collection with all customers from a company *with* their `paymentMethod` relation in one request.

###### Multilevel Expansion / Filtered Expansion

[](#multilevel-expansion--filtered-expansion)

Utilizing closures it is possible to nest expansions and apply filters to the expansions at any level.

```
$company->customers()->expand([
    'paymentMethod' => function(Builder $query) {
    	$query->where('code', '=', 'CR3D17C4RD')
	      ->expand(['nested_relation']);
    },
    'picture',
]);

// Query: companies(...)/customers?$expand=picture,paymentMethod($filter=code eq 'CR3D17C4RD';$expand=nested_relation;$count=true)&$top=40&$count=true
```

See [Filtering](#filtering)

Note: The nesting can be done indefinitely and as complex as you want, but keep in mind there still is a character limit to URLs.

##### Builder Filtering

[](#builder-filtering)

OData reference: [Reference](http://docs.oasis-open.org/odata/odata/v4.0/cs01/part1-protocol/odata-v4.0-cs01-part1-protocol.html#_The_$filter_System)

Filtering allows us to more carefully select which entities we fetch from Business Central.
This allows us to improve performance and exclude irrelevant models from our processing from the start.

A number of different filtering methods exists.
For every filter method an "OR" version exists (eg. `whereDate(...)` -&gt; `orWhereDate(...)`
The `$before` argument is the boolean operator prepended to the query before every clause.

- `where(string $property, $operator = null, $value = null, string $before = 'and')` : `self`

    - Basic where clause
    - Shorthand: `where('displayName', 'John Doe');` is the same as `where('displayName', '=', 'John Doe')`
- `whereIn(string $property, array $values, string $before = 'and')` : `self`

    - Where property in a group of values
- `whereDateTime(string $property, $operator, DateTime $value = null, string $before = 'and')` : `self`

    - Where property is a datetime (`Y-m-d\TH:i:s.v\Z`)
- `whereContains(string $property, $value, string $before = 'and')` : `self`

    - Where property contains the value - Same as SQL `´column´ like '%value%'`
- `whereStartsWith(string $property, $value, string $before = 'and')` : `self`

    - Where property starts with the value - Same as SQL `´column´ like 'value%'`
- `whereEndsWith(string $property, $value, string $before = 'and')` : `self`

    - Where property ends with the value - Same as SQL `´column´ like '%value'`
- `whereGroup(Closure $callback, string $before = 'and')` : `self`

    - Grouped where clause - Example:
        `whereGroup(function(Builder $query) { $query->where('property', 'Foo')->orWhere('property', 'Bar'))`
    - This functionality can be shorthanded as `where(function(Builder $query) { ... })`

Operators:

LogicalOData equiv=eq!=ne&gt;gt&gt;=ge&lt;lt&lt;=le###### Basic Usage

[](#basic-usage-1)

##### Builder Advanced

[](#builder-advanced)

- `clone()` : `self`

    - Clone the current Builder instance with extentions (filters, expands, sorting etc.)
- `cloneWithoutExtentions()` : `self`

    - Clone the current Builder instance without extentions (filters, expands, sorting etc.)

---

Extending Entity Models
-----------------------

[](#extending-entity-models)

The SDK has a range of pre-generated Models it uses to contain and assist the user while using the SDK.
You can replace the class used as the container if you want to - Only requirement is that the model *must* extend `\BusinessCentral\Entity`.

Example:

```
\BusinessCentral\ClassMap::extend('nativeInvoicingSalesCustomers', MyTotallyNewAwesomeCustomerModelReplacementOfAbsoluteDoom::class);
```

This overrides the model class used for all entities of type `customer` in the entire application.

Debugging
---------

[](#debugging)

The SDK logs all requests to and from your application to Business Central for debugging and monitoring purposes.

You can get all log entries from the SDK at any time from `$sdk->request_log`, which returns an array of RequestLog objects.

#### RequestLog Properties

[](#requestlog-properties)

NameTypemethod`string`code`int`uri`string`time`float`options`array`response`mixed`Contribution
============

[](#contribution)

This SDK is not a finished product.
Input, additions and changes are very much encouraged - Fork the repo, make the changes/additions/fixes, and create a pull request.

What's needed?
--------------

[](#whats-needed)

### Schema Overrides

[](#schema-overrides)

A lot of entities on Business Central has read-only fields which are disguised as actual properties but are virtual (like currencyCode on customers is the value of the customer's currency's code property and cannot be changed on the customer itself).

These properties needs to be found and flagged.
Take a look in schema\_overrides.json and follow the syntax for flagging a property as read-only.

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance6

Infrequent updates — may be unmaintained

Popularity38

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity76

Established project with proven stability

 Bus Factor1

Top contributor holds 63.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~34 days

Recently: every ~119 days

Total

34

Last Release

1039d ago

Major Versions

0.5.4 → 1.0.02022-03-15

1.02 → 2.0.02023-07-05

PHP version history (3 changes)0.1.1PHP ^7.3

0.5.1PHP ^7.3 || ^8.0

2.0.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/736a1a2ded6fd311aec3083c7c8880ae4ee472a112e5230bcfb8b500079539f9?d=identicon)[ExeQue](/maintainers/ExeQue)

![](https://www.gravatar.com/avatar/a34d49cb78b21b5454771b18b21ae57ce5135a4874c8c741d196f9ddfe9b8b50?d=identicon)[CoolRunner](/maintainers/CoolRunner)

---

Top Contributors

[![Vassard](https://avatars.githubusercontent.com/u/5878120?v=4)](https://github.com/Vassard "Vassard (7 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![ExeQue](https://avatars.githubusercontent.com/u/23560353?v=4)](https://github.com/ExeQue "ExeQue (1 commits)")[![Fichtme](https://avatars.githubusercontent.com/u/2284107?v=4)](https://github.com/Fichtme "Fichtme (1 commits)")[![pazion](https://avatars.githubusercontent.com/u/687111?v=4)](https://github.com/pazion "pazion (1 commits)")

---

Tags

business-centralsdk

### Embed Badge

![Health badge](/badges/coolrunner-business-central-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/coolrunner-business-central-sdk/health.svg)](https://phpackages.com/packages/coolrunner-business-central-sdk)
```

###  Alternatives

[s-ichikawa/laravel-sendgrid-driver

This library adds a 'sendgrid' mail driver to Laravel.

4139.3M1](/packages/s-ichikawa-laravel-sendgrid-driver)[stechstudio/laravel-zipstream

A fast and simple streaming zip file downloader for Laravel.

4633.7M3](/packages/stechstudio-laravel-zipstream)[laravel-notification-channels/microsoft-teams

A Laravel Notification Channel for Microsoft Teams

1603.0M7](/packages/laravel-notification-channels-microsoft-teams)[spatie/laravel-export

Create a static site bundle from a Laravel app

646127.9k5](/packages/spatie-laravel-export)[erag/laravel-disposable-email

A Laravel package to detect and block disposable email addresses.

226102.4k](/packages/erag-laravel-disposable-email)[truckersmp/steam-socialite

Laravel Socialite provider for Steam OpenID.

1516.7k](/packages/truckersmp-steam-socialite)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
