Application Packaging Standard

Last updated 18-Mar-2019

Module Structure

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.

Metadata

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";
    }
    
}


?>

Basics

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.

Class Declaration

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 @runtimeVersions("2.2-20,2.1-124")
@type(<typename>) Typename definition @type("http://my-company.com/my/webapp/1.0")
@implements(<IList>) Define a set of interfaces being implemented @implements("http://www.aps-standard.org/core/resource/1")

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.

Property Declaration

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(“http://app.ru/resource#Struct”) @type(string[])
@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 @option("en","English")
@pattern(<regexp>) Regexp pattern for value see details in Attributes @pattern('^[a-z][_0-9a-z]*$')
@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 @unit("mb") @unit("mhzh")

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;

Relationship Declarations

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 @link("http://www.aps-standard.org/infrastructure/environment/1")
@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 @defaults("register_globals": true)

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 @link("http://www.aps-standard.org/infrastructure/environment[]")
@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.

Accessing Relation Attributes and Functions

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();

Base Interfaces Methods Implementation

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:

  1. Do not modify $this inside configuire.
  2. 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 Declarations

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(“http://res.url#Class”) @return(string,image/jpeg) @return(integer[])
@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(“http://res.url#Class”,body) @param(string[],path) @param(Class[], body)
@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.

New Types Declaration

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;

Exposing PHP APS Service

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:

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.

CLI Mode

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}]