Download the PHP package academe/xero-php without Composer
On this page you can find all versions of the php package academe/xero-php. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download academe/xero-php
More information about academe/xero-php
Files in academe/xero-php
Package xero-php
Short Description A client implementation of the Xero API, supplying raw data.
License MIT
Homepage https://github.com/academe/XeroPHP
Informations about the package xero-php
Table of Contents
- XeroPHP API OAuth Access
- Intro
- Areas to Complete (TODO)
- Quick Start
- The Response Message
- Message Instantiation
- Response Collections
- Guzzle Exceptions
- Catching Errors
- API Response Structures
- A: Single metadata header; single resource
- B: Single metadata header; collection of resources
- C: Single metadata header; collection of a single resource
- D: Single metadata header; collection of resources
- E: Array of resources
- F: Single resources
- Other Notes
XeroPHP API OAuth Access
PHP library for working with the Xero OAuth API.
Intro
This library tackles the following parts of Xero API access:
- Coordinating the OAuth layer to provide secure access.
- Automatically refreshing expired tokens (for Partner Applications).
- Parsing the response into general nested objects.
This package leaves these functions for other packages to handle, thought does coordinate them:
- All HTTP communications through Guzzle 6.
- OAuth request signing to Guzzle OAuth Subscriber
- OAuth authentication recommended through OAuth 1.0 Client
- Xero provider for OAuth 1.0 Client recommended using Xero Provider for The PHP League OAuth 1.0 Client
- Storage of the OAuth tokens to your own application. A hook is provided so that refreshed tokens can be updated in storage.
- Knowledge of how to navigate the results is left with your application. However, the generic nested data object that the response builds, helps to do this.
This package differs from the excellent calcinai/xero-php package in the following fundamental ways:
- It does not get involved in the process of OAuth authorisation with the end user. You need to handle that yourself.
- It does not have fixed models for the responses, but uses a generic model structure for resources and collections of resources.
- The UK Payroll v2.0 API is supported by this package.
Which package best suites you, will depend on your use-case. Each have pros and cons.
This package needs the OAuth token and secret gained through authorisation to access the API, and the session handler token if automatic refreshing is needed for the Partner Application.
This package does not care what you use at the front end to obtain those tokens. The two packages recommended above to do this are reliable, well documented, and focus on just getting that one job done.
I am mostly focusing on getting this working for the Xero Partner app, as I need a robust librayr that just keeps on running as a scheduled process without losing the tokens and needing a user to re-authenticate. Once a Partner app has been authorised, it should in theory be able to access the Xero account for 10 years, refreshing every 30 minutes. In reality, tokens will get lost - even Xero has downtime that can result in lost authentication tokens.
Areas to Complete (TODO)
- So far development of this package has concentrated on reading from the Xero API. Writing to the API should be supported, but has not gone through any testing at this stage.
- Lots more documentation and examples.
- More consistent handling of errors. The application should not have to go huntiong to find out if the error is in the configuration, the network, the remote application, the syntax of the request etc. Those details should all be handed to the application on a plate.
Quick Start
Now we have a client to send requests.
This is a refreshable client, so if using the Xero Partner app, it will refresh its token
automatically when it expires and inform your application via the tokenRefreshCallback
.
After sending a request, you can check if the token was refreshed for any action you may want to perform as a result:
If the token is refreshed, then the new token will have been stored by your app through
the tokenRefreshCallback
.
If you want to refresh the tokens explicitly, before you hit an expired token response, then it can be done like this:
That may be more convenient to do, but be aware that unless you set a guard time, there may be times when you miss an expiry and the request will return an expired token error.
You may want to check that the expiry time is approaching on each run, and renew the token explicitly. This check can be used to see if we have entered a "guard window" preceding the expected expiry time:
The Response Message
Message Instantiation
The ResponseMessage
class is instantiated with the response data.
Either the Response
object or the data extracted from the response can be
used to initialise the ResponseMessage
:
php if ($result->isCollection()) { $collection = $result->getCollection(); }
if ($result->isResource()) { $resource = $result->getResource(); }
if ($result->isEmpty()) { // No resources - check the metadata to find out why (TODO). }
There may be further collections of resources deeper in the data, such as a list of addresses for a contact.
Response Dates and Times
An attempt is made to convert all dates and times to a Carbon
datetime.
Xero mixes quite a number of date formats across its APIs, so it is helpful to
get them all normallised.
Formats I've found so far:
- "/Date(1509454062181)/" - milliseconds since the Unix epoch, UTC.
- "/Date(1439813704613+0000)/" - milliseconds since the Unix epoch, with a timezone offset.
- "2017-10-20T16:04:50" - ISO UTC time, to the second.
- "2017-10-31T12:50:15.9920037" - ISO UTC timestamp with microseconds.
- "2017-09-25T00:00:00" - ISO UTC date only.
I'm sure there will be more. These fields are recognised solely through the suffix to their name at present. Suffixes recognised are:
- UTC
- Date
- DateTime
- DateOfBirth (as a prefix)
Pagination
There is no automatic pagination feature (automatically fetching subsequent pages) when iterating over a paginated resource. A decorator class could easily do this though, and that may make a nice addition to take the logic of "fetching all the matching things" that span more than one page away from the application (ideally the application would make a query, then loop over the resources and each page would be lazy-loaded into the collection automatically when going off the end of the page).
All other datatypes will be either a scalar the API supplied (string, float, int, boolean)
or another ResponseData
object containing either a single Resource
(e.g. "Invoice")
or a ResourceCollection
(e.g. "CreditNotes").
Resource Properties
Accessing properties of a resource object is case-insensitive. This decision was made due to the mixed use of letter cases throughout the Xero APIs.
A resource will have properties. Each property may be another resource, a resource collection, a date or time, or a scalar (string, integer, float).
Accessing a non-existant property will return an empty Resource
.
Drilling deeper into an empty resource will give you further empty resources.
But do be aware that when you hit a scalar (e.g. a string) then that is what you will get
back and not a Resource
object.
The API sometimes returns a null
for a field or resource rather than simply omitting the
field. Examples are the pagination
field when fetching a single payrun
, or the problem
field when there is no problem.
In this case, when you fetch the value, you will be given an empty Resource
object
instead.
Guzzle Exceptions
By default, the Guzzle client will throw an exception if it receives a non 20x HTTP response. When this happens, the HTTP response can be found in the exception.
Handling non-20x messages like this may not be convenient, so Guzzle can be told not to
throw an exception using the exceptions
option:
Note: this package now switches off Guzzle exceptions by defaul. You can turn them back on using this parameter if that is desirable. Token refreshing will work both with or without excpetions being enabled.
This option can be used on each request, or set as the default in the ClientProvider
instantiation options.
This package is designed not to care which approach you take. However, not throwing an
exception often makes sense, because even non-20x responses nearly always contain a response
body with information the application is going to need to log or to make a decision.
Catching Errors
There are numerous sources of error, and these are reported in many different ways, and with different data structures. The aim of this package will be to try to normalise them, but in the meantime here is a list of those we know:
- OAuth errors
- Request construction errors, such as an invalid UUID format
- Invalid resource errors, such as a missing resource or incorrect URL
- Data errors such as trying to retrieve beyond the last page of results
The places where error details cna be found are:
- OAuth errors will be returned as URL-encoded parameters in the response body.
The
OAuthParams
class can parse these details and provide some interpretation. - Request construction errors are returned TBC
API Response Structures
Each response will be in one of a number of structures. The structures listed below have been identified so far, with the aim that all will be recognised automatically and normalised to a single resource or collection.
A: Single metadata header; single resource
The resource is in a single node, usually named after the resource content, but not always. Examples include fetching a single Payrun in the GB Payroll v2.0 API.

B: Single metadata header; collection of resources
The resources are in an array under a single node, usually named after the resource content, but not always. Examples include fetching a multiple Payruns in the GB Payroll v2.0 API. Paging metadata is in an object of its own.

C: Single metadata header; collection of a single resource
Some APIs will return both a single resource and multiple resources in an array, with no paging metdata. Distinguishing between the response to requesting a single resource, or matching a single resource in a resource collection, is not possible; the response looks the same withou looking at more details of the content of the resource. Examples include fetching a single payment from the Accounting v2.0 API.

D: Single metadata header; collection of resources
This structure includes some metadata at the root node, including paging details that are not wrapped into an object. Examples include fetching a multiple files from the Files v1.0 API.

E: Array of resources
Some APIs will return an array of resources with no metadata at all, no paging details, no source details.

F: Single resources
Similar to format E, the response contains a single resource, not wrapped into a field or object, and with no metadata to provide context.

There are a number of different formats used to deliver error messages and exceptions (at least four different structures). These will be documented shortly, as they need to be handled using the same rules.
I suspect at least two of these stcutures can be merged into one.
Other Notes
I have noticed the occassional 401 which then works on a retry. Using the Guzzle retry handler would be a good move to avoid unnecessary errors when processing large amounts of data.