Download the PHP package sitepark/oparl-client without Composer

On this page you can find all versions of the php package sitepark/oparl-client. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package oparl-client

codecov phpstan php php php php php

English | Deutsch

OParl PHP Client

Note: This project was developed with extensive use of AI. Contributions created with the help of AI are accepted.

A PHP client for OParl 1.0 and 1.1, the standard interface of German council information systems (Ratsinformationssysteme). It maps all OParl object types to PHP classes, resolves references between them, iterates over paginated lists and supports the incremental update mechanism of the specification.

Requirements

Composer asks whether to allow the plugin of php-http/discovery, which finds the installed http client. The client works either way; with the plugin allowed, Composer also installs a PSR-18 client and PSR-17 factories automatically if none is installed yet.

Quick start

Almost all properties are optional in OParl, so most getters return null if the server did not send the value. Static analysis (PHPStan, Psalm) will remind you to check them; the examples in this README leave the checks out for brevity.

Usage

Creating a client

new OparlClient() finds an installed PSR-18 client and PSR-17 request factory via php-http/discovery. All arguments are optional, pass them by name:

Argument Default
httpClient an installed PSR-18 client, found by php-http/discovery
requestFactory an installed PSR-17 request factory
userAgent oparl-client/<version>
logger NullLogger

Every request is sent with Accept: application/json. A userAgent that names your application and a way to contact you helps the operators of OParl servers.

A client can be reused for all requests, and it can be registered as a service in a dependency injection container.

Timeouts, redirects and proxies

Timeouts, redirects and proxies are configured in the PSR-18 client you pass to the OparlClient. Configure timeouts: by default, neither Symfony HttpClient nor Guzzle limits the total duration of a request, so a server that answers very slowly can hold up your application for a long time.

Symfony HttpClient follows redirects by default:

Guzzle never follows redirects when used as PSR-18 client, regardless of its allow_redirects option. Wrap it with the RedirectPlugin of php-http/client-common:

Redirects

OParl servers may redirect to their canonical URLs. If the PSR-18 client does not follow the redirect, the request fails with an OparlHttpException with status code 301 or 302. Note that new OparlClient() without arguments discovers Symfony HttpClient if it is installed, but Guzzle if that is the only PSR-18 client, which then does not follow redirects; pass the client explicitly as shown above.

Resolving objects

get() requests an object and maps it to the given class:

If the type of an object is not known in advance, getAny() returns the matching subclass of OparlObjectV1, determined by its type property:

Objects of vendor-specific or unknown types are returned as plain OparlObjectV1, with their properties available via getAdditionalProperties().

References

OParl objects refer to each other by URL. These URLs are wrapped in an OparlReference, which knows the type of the referenced object and requests it on demand:

Lists of references, e.g. the originators of a paper, are list<OparlReference<…>>:

References are resolved through the client that read the object. When an object is serialized, a reference is written as its URL, just like in the original JSON.

Lists and pagination

Lists of objects, e.g. all meetings of a body, are returned as OparlList. The server may split them into pages; an OparlList is one page.

all() is a generator: the next page is only requested when the elements of the previous page have been consumed, so leaving the loop early saves requests. all() starts with the page it is called on, and every call starts there again.

If a page can not be fetched, all() fails with the exception of that page, e.g. an OparlHttpException whose getUri() is the URL of the page, so a partial result is never mistaken for the complete list. Empty pages are skipped, and iteration stops with a warning if a next link points to a URL that has already been requested. Cycles are detected by these URLs only, not by the self links of the pages, so a server that sends the same self link on every page does not cut the list short.

Duplicates

Some servers deliver the same object more than once, on one page or on different pages, e.g. when data changes while you are paging. Objects are identified by their id; use it as array key to remove duplicates:

Objects have no equals() method: compare getId(), and getModified() to detect changes.

Filters

Lists can be filtered with the URL parameters defined by the specification:

Class URL parameter
Created created_since, created_until
Modified modified_since, modified_until
OmitInternal omit_internal
Limit limit (servers may ignore it)
QueryParam any other parameter

The specification requires a full date-time including the time zone, e.g. 2024-08-16T00:00:00+02:00. Created and Modified accept any DateTimeInterface and send it with the offset of its time zone, without fraction of seconds; strings are sent as they are. Pass all values unencoded; the client URL-encodes them. withQueryParams() returns a new reference and keeps the existing query of the URL.

Keeping a local copy up to date

OParl 1.1 defines an update mechanism: after an initial import, request only the objects modified since the last run. With modified_since, the server also returns deleted objects, marked with deleted, so they can be removed locally.

$lastRun is only advanced after a complete run: if a page can not be fetched, all() throws an exception and the next run starts again from the previous point in time.

Vendor-specific properties

OParl servers may add properties with a vendor prefix, e.g. "BeispielHersteller:faxNumber". These and all other properties that are not mapped are kept as decoded by json_decode(..., true), JSON objects as associative arrays, and are written back on serialization:

Invalid values

Values that do not match the type required by the specification do not fail the whole response, e.g. URLs where embedded objects are required, a number where a reference is expected, or a date that can not be parsed. Invalid elements are left out of a list, an invalid single value is null, and a warning is logged. The original value is kept as additional property under the same name, so it is not lost and is written back on serialization:

A single value where a list is required, e.g. "email": "[email protected]", is read as a list with that value. A reference may also be sent as embedded object; its id is used then. URLs with characters that are not allowed, e.g. spaces, are percent-encoded; valid URLs are kept exactly as sent. Responses are read as UTF-8: a byte order mark is ignored, and bytes that are no valid UTF-8, e.g. of a server sending Latin-1, are replaced with U+FFFD (�).

Error handling

Every failed request throws an OparlException (a RuntimeException). getUri() returns the URL of the failed request, getPrevious() the underlying exception, if any.

Exception Cause
OparlHttpException status code other than 2xx; getError() returns the OParl error object, if sent
OparlParseException the response is no valid JSON or no JSON object
OparlConnectionException the http client failed, e.g. the server could not be reached or did not answer in time
OparlException other errors, e.g. an invalid URL, an empty response or a non-http URL

PSR-18 does not distinguish timeouts from other network errors, so a timeout is an OparlConnectionException as well. The same exceptions are thrown while iterating over the pages of a list.

Programming errors are reported with the standard exceptions, e.g. an InvalidArgumentException for Limit::of(0).

Object types

Class OParl type
OparlObjectV1 common base class (id, type, created, modified, deleted, keyword, license, web)
OparlSystem oparl:System
OparlBody oparl:Body
OparlLegislativeTerm oparl:LegislativeTerm
OparlOrganization oparl:Organization
OparlPerson oparl:Person
OparlMembership oparl:Membership
OparlMeeting oparl:Meeting
OparlAgendaItem oparl:AgendaItem
OparlPaper oparl:Paper
OparlConsultation oparl:Consultation
OparlFile oparl:File
OparlLocation oparl:Location

The classes are in the namespace SP\OparlClient\V1\Objects; OparlTypes maps the type URLs of OParl 1.0 and 1.1 to them.

Objects are immutable (readonly). They can be created with named arguments, e.g. for tests:

Almost all properties are optional in OParl, so every getter returns null if the server did not send the value, also for numbers and booleans (getOrder(): ?int, getCancelled(): ?bool). The only exception is isDeleted(), which is false then, since the specification only marks deleted objects.

Points in time (date-time) are DateTimeImmutable with the offset sent by the server. Dates (date) are DateTimeImmutable as well, at the start of the day in Europe/Berlin. Values that do not follow the specification are read tolerantly: a date-time without offset is interpreted in German time (Europe/Berlin), a date where a date-time is expected as start of that day, a date-time where a date is expected as its date; values that can not be parsed at all are read as null, logged and kept as additional property. URLs are strings.

Serialization

All objects implement JsonSerializable and are written in the format of the specification:

Properties without value are left out, as the specification recommends; deleted is only written if it is true. Dates are written as 2024-01-21, points in time as 2024-01-21T18:00:00+01:00, references as URL. Additional properties are written as well, so objects read from a server are written back without loss.

Storing objects

To store objects, e.g. in a database or cache, write them as JSON and restore them with the client; references in the restored objects are resolved through that client again:

Objects can also be stored with serialize(), e.g. by a PSR-6 cache. References can not be resolved after unserialize() then, since they lose the connection to the client; their getUri() still works. List pages hold the logger of the client and are not meant to be serialized; store their elements, or the page as JSON.

Security

The client follows every URL a server returns: references and pagination links, and your http client follows redirects. It reads responses of any size into memory. It is meant for OParl servers you trust. If your application lets users enter the endpoint, restrict the hosts it may reach, e.g. with a proxy or network rules, since a malicious server could otherwise make it request internal hosts (SSRF). Symfony HttpClient offers NoPrivateNetworkHttpClient for this.

Logging

Pass a PSR-3 logger to receive the messages of the client:

Level Message
warning invalid values that were ignored, pagination stopped because of a cycle
debug every request

Values sent by a server are stripped of control characters before they are logged.

Development

The tools are installed with phive by composer install.

Commit messages follow Conventional Commits. To check them locally, enable the hook:

SchemaCoverageTest and SchemaValuesTest check the object classes against the OParl 1.1 schema in test/resources/schema/1.1: every property must have a getter of a matching type, and every value must arrive at its getter and be written back unchanged.

License

MIT. The OParl schema files in test/resources/schema/1.1, used for testing only, are licensed under CC BY-SA 4.0 by the OParl authors.


All versions of oparl-client with dependencies

PHP Build Version
Package Version
Requires php Version ^8.1
php-http/discovery Version ^1.19
psr/http-client Version ^1.0
psr/http-factory Version ^1.0
psr/http-message Version ^1.1 || ^2.0
psr/log Version ^1.1 || ^2.0 || ^3.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package sitepark/oparl-client contains the following files

Loading the files please wait ...