The APS PHP Runtime library provides a way to simplify creation of PHP-based APS applications. It allows you to work with APS resources as PHP classes and automates REST communication with APS Controller.
In this document:
Each APS type is represented by a PHP module. The module path is specified in the <code> element of the corresponding service declaration in application metadata.
A resource schema, used to generate an APS type, is defined in a PHP module by means of meta-information (annotations). PHP runtime provides an ability to generate JSON schemas from PHP modules, basing on the metadata.
Example of a simple PHP web APS application: download
<?php
require_once "aps/2/runtime.php";
/**
* Main class of my web application
* @type("http://my-company.com/my/webapp/1.0")
* @implements("http://www.aps-standard.org/core/resource/1")
*/
class MyWebApp extends ResourceBase
{
/**
* @type(string)
* @title("Administrator Name")
*/
public $adminName;
/**
* @title("Administrator password")
* @encrypted
* @type(string)
*/
public $adminPassword;
/**
* @type(string)
* @format(email)
* @title("Administrator E-Mail")
*/
public $adminEmail;
/**
* @link("http://parallels.com/aps/types/pa/database/mysql/1.0")
*/
public $db;
/**
* @link("http://aps-standard.org/types/core/web-environment/1.0")
* @required
* @requirement(engines == 'php' && php.version > '5.0')
*/
public $environment;
/**
* This method will be called on provision of application
*/
public function provision()
{
$dbh = new PDO($this->db->dsn, $this->db->login, $this->db->password);
$stmt = $dbh->prepare("INSERT INTO configuration (login, password, email) VALUES(?, ?, ?)");
$stmt->execute(array($this->adminName, $this->adminPassword, $this->adminEmail));
}
/**
* This method will be called on reconfiguration of application
*/
public function configure($new)
{
$this->adminName;
$dbh = new PDO($this->db->dsn, $this->db->login, $this->db->password);
$stmt = $dbh->prepare("UPDATE configuration SET login = ?, password = ?, email = ?");
$stmt->execute(array($new->adminName, $new->adminPassword, $new->adminEmail));
}
/**
* Additional method called from appliction UI or API
* @verb(POST)
* @path("/blog")
* @param(string,query)
* @param(string,query)
*/
public function blog($title, $entry = "new blog entry")
{
echo "Blog Entry [$title]\n$entry\n";
}
}
?>
To start an APS-based resource declaration, one should include the APS PHP Runtime library as below:
require_once "aps/2/runtime.php";
To define APS meta-information, one should use a DocComment block (/** … */) before a defined object.
Note
A comment should start with slash double-star ‘/**’ to work properly.
To define an application resource, one should define a usual PHP class, based on ResourceBase and provide meta-information in a comment before class declaration.
/**
* Main class of my web application
* @runtimeVersions("2.2-33,2.1-269,2.0-340")
* @type("http://my-company.com/my/webapp/1.0")
* @implements("http://www.aps-standard.org/core/resource/1.0")
*/
class MyWebApp extends ResourceBase
{
...
The following annotations are allowed here:
Annotation |
Description |
Example(s) |
---|---|---|
@runtimeVersions(<VList>) |
required Rruntime versions |
|
@type(<typename>) |
Typename definition |
|
@implements(<IList>) |
Define a set of interfaces being implemented |
|
A controller will use <typename> to learn the APS type of the resource which is managed by the service. The controller will use <IList> to learn what APS interfaces are implemented by the APS type.
runtimeVersions is optional annotation. It shows which versions of PHP runtime are required by the application.
PHP runtime will throw an exception if its version is below the required ones.
For example, in case of @runtimeVersions(“2.2-20,2.1-124”), compatible versions are:
2.2-NN, where NN >= 20
2.1-NN, where NN >= 124
X.Y-NN, where X.Y > 2.2
Example:
/**
* Class contexts
* @type("http://user-mgmt.demo.apsdemo.org/methods/contexts/2.0")
* @implements("http://aps-standard.org/types/core/resource/1.0","http://aps-standard.org/types/core/suspendable/1.0")
*/
class contexts extends \APS\ResourceBase
{
Note
Brackets [] are commonly used in PHP runtime annotations to identify an array type, or collection in case of a link.
Define APS resource properties as public PHP properties, followed by the normal variable declarations.
Do not define an APS resource property as a static property.
To specify the type of property, use the @type
APS decorator.
...
class MyWebApp extends ResourceBase
{
...
/**
* @type(string)
* @title("Administrator password")
* @encrypted
*/
public $adminPassword;
/**
* @type(string)
* @format(email)
* @title("Administrator E-Mail")
*/
public $adminEmail;
Below is a list of annotations for attributes of properties.
The only required attribute is @type
.
Simple properties:
Annotation |
Description |
Example(s) |
---|---|---|
@type(<typename>) |
Property type definition (primitive, object, or structure). Use brackets to declare an array. |
@type(string)
@type(object)
@type(SomeStructure)
@type( |
@required |
Property must be filled in |
@required |
@readonly |
User can’t change property in UI. Such property can be change only by application itself, from endpoint side. |
@readonly |
@final |
Property should be filled in during resource provisioning and can’t be changed later |
@final |
@encrypted |
Controller should make sure that the value of property is encrypted in persistent storage. Such property is not visible to customer (in UI or if ‘impersonated’ as customer). It is visible only to application. |
@encrypted |
@minLength(<len>) |
Defines minimum allowed length for argument in characters |
@minLength(10) |
@maxLength(<len>) |
Defines maximum allowed length for argument in characters |
@maxLength(20) |
@title(<text>) |
Defines label for property Note: if title is omitted, property is not displayed in auto-genetated UI |
@title(“Login”) |
@description(<text>) |
Defines long description for property |
@description( “User login name on company domain”) |
@headline |
Identifies that property is used to represent a resource. In the platform, ‘headline’ properties are shown in Application Service Reference RT Wizard. If none is marked as ‘headline’, all properties are shown in the Wizard. |
@headline |
@format(<format>) |
Defines format restriction, see details in Attributes |
@format(email) |
@option(<key>, <title>) |
Enumeration element, can be placed several times for multiple options |
|
@pattern(<regexp>) |
Regexp pattern for value see details in Attributes |
|
@access(<scope>,boolean) |
Restricts or allows access to the property in particular security scope. see details in Access Attributes |
@access(referrer,false) @access(public,true) |
@unit(unit of measure) |
Is applied to properties of type Limit, Counter or Usage Refer to: Counters One of the following unit types can be declared: kb, mb, gb, unit, item, mb-h, mhzh, item-h |
|
Note
The default
attribute is an exception since it is defined by direct assignment of a value to the declared
property, for example:
/**
* @type(string)
* @title("Protocol")
* @description("Protocol")
* @required
*/
public $protocol = "https";
Brackets ‘[]’ in the declaration of the type
attribute specify that the property refers to an array of values of a given type.
The array attributes (in addition to the above, except the type
) are:
Annotation |
Description |
Example(s) |
---|---|---|
@type(<typename>[]) |
Array type definition |
@type(string[]) |
@minItems |
Defines minimum number of items allowed |
@minItems(2) |
@maxItems |
Defines maximum number of items allowed |
@maxItems(5) |
@uniqueItems |
Requires all items to be unique |
@uniqueItems |
Property type can be a structure. If a structure is defined in a module, it can be referred directly. Otherwise, there must be a resource type prefix, for example: http://aps-standard.org/types/core/resource/1.0#Counter
Examples:
/**
* Counter is a structure from http://aps-standard.org/types/core/resource/1.0 core type
* @type("http://aps-standard.org/types/core/resource/1.0#Counter")
* @description("Total Memory usage")
* @unit("mb")
*/
public $memoryusagetotal;
To define relationship with other aps resources, use the @link
decorators.
Example:
class MyWebApp extends ResourceBase
{
...
/**
* @link("http://www.aps-standard.org/infrastructure/environment/1.0")
* @required
* @requirement(engines == 'php' && php.version > 5.0)
*/
public $environment;
Annotation |
Description |
Example(s) |
---|---|---|
@link(<typename>) |
Link to resource of the given APS type |
|
@required |
There should be a resource linked |
@required |
@requirement |
Defines a requirement expression for the linked resource. May be used multiple times, all conditions to be met |
@requirement(php.version > 5.0) |
@defaults |
Assigns properties to the new resource |
|
To define a collection, use brackets after the link type:
class MyWebApp extends ResourceBase
{
...
/** @link("http://www.aps-standard.org/infrastructure/environment/1.0[]") */
public $containers;
After such declaration in $this->containers will be a list of container resources.
Annotation |
Description |
Example(s) |
---|---|---|
@link(<typename>[]) |
Collection of links to a resource of the given APS type |
|
@required |
There should be as minimum one linked resource |
@required |
@requirement |
Defines a requirement expression for the linked resource. May be used multiple times, all conditions to be met |
@requirement(php.version > 5.0) |
Note
In the @link
decorator, you can specify an APS type either without version, with the full version, or with
the major version only. Follow the Version Compatibility recommendations to choose the right way.
If an application needs to know about creation or deletion of a link to resource <linkname>, the application script should define the two following methods:
<linkname>Link($resource)
<linkname>Unlink($resource)
Note
Define link/unlink methods only when it’s necessary. Omitting them will improve performance.
For the above example of linked resources Link and Unlink methods should be defined as follows:
public function containersLink()
{
}
public function containersUnlink()
{
}
PHP runtime returns HTTP status 204 if the Link
method is not present, or does not return anything.
For the Unlink
method, the return HTTP status is always 204.
Relations can be accessed as $object->linkName. Even if a relation is not defined, $object->linkName is not null, but is an instance of CollectionProxy or ResourceProxy classes. To check whether relation is actually defined, use isEmpty method.
Method works both for collections and singular relations. In case of collection, isEmpty is true if there are no elements in the collection.
...
public function provision()
{
if ($this->user->isEmpty()) {
// user is not assigned yet
}
}
Collection works as an array of resources, as follows:
...
public function disable()
{
// put on hold the account and suspend all vpses
foreach ($this->vpses as $vps) {
\APS\Logger::get()->info("VPS: ".$vps->aps->id);
// call function of VPS resource:
$vps->suspend();
}
An attribute of a singular relation can be accessed as $object->linkName->attributeName.
Function is called as $object->linkName->functName($arg1, $arg2, …)
...
public function provision()
{
// provision VPS
$this->context->createKey($this->user->login, $this->user->password);
Resources are retrieved from APSC once any attribute or function of the relation is called. Further requests to the relation use previously obtained resources, which are stored in cache. If you need to renew the cache of the relation, use reload function. It works both for collection and singular relation.
...
$this->user->reload();
$this->vpses->reload();
Implementation of the methods defined in the interfaces mentioned in @implements of the Class Declaration. All methods must be implemented.
A set of parameters in methods implementation should match the declaration in the base interfaces.
...
class MyWebApp extends ResourceBase
{
...
/**
* This method will be called on reconfiguration of the application
*/
public function configure($new)
{
$dbh = new PDO($this->db->dsn, $this->db->login, $this->db->password);
$stmt = $dbh->prepare("UPDATE configuration SET login = ?, password = ?, email = ?");
$stmt->execute(array($this->adminName, $this->adminPassword, $this->adminEmail));
}
The core resource type (http://www.aps-standard.org/core/resource/1.0) declares four methods to be implemented. They provide the basic CRUD operations:
provision() - creation of a resource
configure($newConfiguration) - reconfiguration of a resource
unprovision() - removal of a resource
retrieve() - get the actual resource configuration
_getDefault() - get default values of a resource properties. It is called before provision. Must return an array of (property => value) pairs. Example: array(“prop1” => “value1”, “prop2” => “value2”).
Core suspendable type http://aps-standard.org/types/core/suspendable/1.0 declares methods which are called when subscription is placed on hold, cancelled, resumed from hold.
disable() - disable current resource. Called when subscription is placed on hold or cancelled.
enable() - enable current resource. Called when subscription is resumed.
configure receives old properties in current object ($this), and new properties in function parameter ($newConfiguration). If you change any property in $this in configure, PHP runtime will report properties back to the platform and thus can overwrite new values.
There are 2 ways to handle this:
Do not modify $this inside configuire.
If you change any property in $this, make sure to copy other properties from $new.
Simple way to copy properties from $new to $this:
public function configure($new) {
$this->_copy($new);
....
New methods may be declared as operations on resource types. To define a class method as an exposed resource operation, @verb and @path decorators should be used.
...
class MyWebApp extends ResourceBase
{
...
/**
* Additional method called from application UI or API
* @verb(POST)
* @path("/blog")
* @description("Create new blog entry")
* @param(string,query)
* @param(string,query)
*/
public function blog($title, $entry = "new blog entry")
{
echo "Blog Entry [$title]\n$entry\n";
}
Annotation |
Description |
Example(s) |
---|---|---|
@verb(<verb>) |
Bind an operation to a REST HTTP method allowed values - GET / POST / PUT / DELETE |
@verb(POST) |
@path(<path>) |
Define sub-path under service to bind the operation. Base URL of the method depends on the value of the @static property. |
@path(“/blog”) |
@return(<type>,<content-type>) |
Specify a type and (optionally) MIME Media Type of returned value |
@return(string,text/plain)
@return(Class)
@return( |
@description(<text>) |
Specify method description |
@description(“Create new blog”) |
@param(<type>,<kind>) |
Specify parameter of call, should be used for every parameter, kind should be one of path, body, query |
@param(string, query)
@param( |
@param(string,body,<content-type>) |
body parameter is json by default. For other types, specify content-type, and type ‘string’ |
@param(string, body, image/jpeg) |
@static |
Defines a method as static, there is no resource to be fetched from a controller to call the method. Defaults to “false”. |
@static |
Default values of the parameters are defined in function declaration, as in this example:
public function blog($title, $entry = "new blog entry")
“new blog entry” is the default value.
If a parameter does not have default value, it is treated as required. Exception will be thrown if such parameter is missed.
@param and @return annotations can use classes as their types. If class is declared in current module (in current resource), or in resources it implements, class can be referred directly. Otherwise, there must be a resource type prefix.
In case of an error, the method may throw an exception. The exception should be based on the APS Exception class in order to be correctly handled by the controller API.
An APS type may define additional types in order to pass types as parameters to methods or use as properties.
Types are defined as PHP classes, in the module they belong, and are transformed into Structures, when JSON schema is built from PHP module.
Example of an additional type defined as part of an APS type:
class Contact
{
/** @type(string) */
var $firstName;
/** @type(string) */
var $lastName;
/** @type(string) */
var $email;
/** @type(string) */
var $phone;
}
/**
* Class SomeUser
* @type(http://www.odin.com/mail/exchange/mailbox/1.0))
* @implements(http://www.aps-standard.org/core/resource/1.0)
*/
class SomeUser extends ResourceBase
{
/**
* @type(Contact)
* @description("Administrative Contact")
*/
public $adminContact;
...
You can also use a PHP class to aggregate several properties together as an additional structure, including arrays. Decorate these properties in the same way as the main class. See Property Declaration _.
If a structure is defined outside off the current type, you need to refer to it using the type ID, as follows:
http://resource.type#Structure
For example, the Notification structure in an event handler declaration:
/**
* @verb(POST)
* @path("/onUserChanged")
* @param("http://aps-standard.org/types/core/resource/1.0#Notification",body)
*/
public function onUserChanged($notification) {
Usage structure in property declaration:
/**
* @type("http://aps-standard.org/types/core/resource/1.0#Usage")
* @description("Diskspace usage")
* @unit("mb")
*/
public $diskspace;
To expose a PHP service in a PHP file like webapp.php
,
one should bind it to some service URL under the running PHP interpreter.
For Apache web server, it may be done with the help of an Alias
instruction of mod_alias
:
Usually this is accomplished by an environment resource which installs an application.
HTTP requests that are available after such binding:
POST https://server.uri/base/path/webapp
- creation of a resource
PUT https://server.uri/base/path/webapp/123456-12344-2233232
- update of a resource
DELETE https://server.uri/base/path/webapp/123456-12344-2233232
- removal of a resource
GET https://server.uri/base/path/webapp/123456-12344-2233232
- get the actual resource configuration
GET https://server.uri/base/path/webapp/$schema
- retrieve the schema of resource, like defined at Type Definition
Note
123456-12344-2233232 - stands for the ID of the resource created.
To generate schema from command line, the following command can be used:
php /some/install/path/scripts/webapp.php '$schema'
Note
apsbuild tool uses PHP runtime to build the schemas. If application is based on PHP runtime, it is strongly NOT recommended to edit schemas directly. Edit PHP modules first, and then build schemas using apsbuild tool.
Starting from version 2.0-331, PHP runtime can process HTTP requests in CLI mode. For this, it is needed to pass HTTP request, headers and request body to standard input of corresponding script.
For example:
php sampleresource.php < request.txt
Where request.txt file contains the following sample request:
POST /sampleresource/73a07050-b4ef-406a-a7fa-3596675a70c7/chkdomain?entry=plan HTTP/1.1
APS-Instance-Id: 73a07050-b4ef-406a-a7fa-3596675a70c7
Content-type: application/json
content-length: 50
{"type":1,"name":"mydomain.mobi","plans":[10003]}
Response is printed to standard output, and contains HTTP headers and response body.
Example response:
HTTP/1.1 200 OK
Cache-Control: no-cache, must-revalidate
Expires: 0
Content-Type: application/json
X-Powered-By: APS PHP Runtime 2.0-331
content-length: 87
[{"name":"www.mydomain.mobi","plan":10003},{"name":"www.mydomain.mobi","plan":10003}]