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
composer require coolrunner/business-central-sdk
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.
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'
]);
Business Central for PHP uses an internal query builder to navigate and fetch entities.
$query = $sdk->query();
$query = $sdk->query();
// Navigate using ->navigateTo(...) (or shorthand ->to(...))
$query->to('Company','CompanyName')->to('invoicingCustomers'); // Equivalent of fetching from 'Company(CompanyName)/invoicingCustomers'
$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
// Fetch a single company
$company = $sdk->company('CompanyName');
// Fetch all companies available to the authorized user
$companies = $sdk->companies();
Class for Entity fetched from Business Central
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.
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 to see if the relation is a collection type or not.
fill(array $attributes)
: Entity
save()
: bool
validate()
: bool
save()
getEntityType
: EntityType
query()
: Builder
toArray()
: array
Container class for Entities fetched from Business Central
None
find(string|array $id, $default = null)
: Entity | null
$default
on failurecreate(array $attributes)
: Entity
update(string|array $id, array $attributes)
: Entity
delete(string|array $id)
: bool
first($default = null)
: Entity | null
| mixed
$default
is emptycount()
: int
all()
: array
getEntitySet
: EntitySet
query()
: Builder
toArray()
: array
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.
None
navigateTo(string $component, string $id = null) | to(string $component, string $id = null)
: self
fetch()
: EntityCollection
count()
: int
exists()
: bool
limit(int $limit = null)
: self
|int
$limit
is set, else returns the current limitpage(int $page = null)
: self
|int
$page
is set, else returns the current pagenextPage()
: self
prevPage()
: self
orderBy($property, string $direction = 'asc')
: self
$field
property can be an array containing multiple conditions ( ['property' => 'direction'] )orderByAsc(string $property)
: self
orderByDesc(string $property)
: self
OData Reference: Reference
expand(array $relations)
: self
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.
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
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.
OData reference: Reference
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(...)
-> 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
where('displayName', 'John Doe');
is the same as where('displayName', '=', 'John Doe')
whereIn(string $property, array $values, string $before = 'and')
: self
whereDateTime(string $property, $operator, DateTime $value = null, string $before = 'and')
: self
Y-m-d\TH:i:s.v\Z
)whereContains(string $property, $value, string $before = 'and')
: self
´column´ like '%value%'
whereStartsWith(string $property, $value, string $before = 'and')
: self
´column´ like 'value%'
whereEndsWith(string $property, $value, string $before = 'and')
: self
´column´ like '%value'
whereGroup(Closure $callback, string $before = 'and')
: self
whereGroup(function(Builder $query) { $query->where('property', 'Foo')->orWhere('property', 'Bar'))
where(function(Builder $query) { ... })
Operators:
Logical | OData equiv |
---|---|
= | eq |
!= | ne |
> | gt |
>= | ge |
< | lt |
<= | le |
clone()
: self
cloneWithoutExtentions()
: self
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.
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.
Name | Type |
---|---|
method | string |
code | int |
uri | string |
time | float |
options | array |
response | mixed |
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.
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.