Version: 0.4.1

Download

Subversion URI: http://headzoo.com/subversion/grimm/trunk

Requirements

PHP 5.1 or greater

Apache web server

License

GPL 3

  1. Overview
  2. Installing
  3. Bugs
  4. Creating a Service
  5. Testing the Service
  6. Doc Comments
  7. Arrays
  8. Custom Types
  9. URL Rewriting

Overview

Grimm is a SOAP and WSDL application for PHP. Grimm makes it easy to create SOAP powered web services. With Grimm, creating a web services is as simple as creating a PHP class, and exposing one or more public methods.

Creating a web service is just a matter of creating a PHP class. Here is an example Calculator web service to either add, or subtract two numbers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
class Calculator
{
	/**
	 * Adds two numbers
	 *
	 * @param int $first The first number
	 * @param int $second The second number
	 * @return int
	 */
	public function add($first, $second)
	{
		return $first + $second;
	}
 
	/**
	 * Subtracts two numbers
	 *
	 * @param int $first The first number
	 * @param int $second The second number
	 * @return int
	 */
	public function sub($first, $second)
	{
		return $first - $second;
	}
}

And that’s it! Just save the class in a file named after the class with a .pws extension (i.e. Calculator.pws) and place the script in Grimm’s /services directory. You can then view the service’s WSDL document using a URL like this:

http://mysite.com/Grimm/services/Calculator?wsdl

You’ll see something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<wsdl:definitions targetNamespace="http://Target">
<!--Generated by Grimm v0.1 / http://headzoo.com/grimm--><wsdl:message name="addResponse">
<wsdl:part name="addReturn" type="xsd:int"/>
</wsdl:message><wsdl:message name="addRequest">
<wsdl:part name="first" type="xsd:int"/>
<wsdl:part name="second" type="xsd:int"/>
</wsdl:message><wsdl:message name="subResponse">
<wsdl:part name="subReturn" type="xsd:int"/>
</wsdl:message><wsdl:message name="subRequest">
<wsdl:part name="first" type="xsd:int"/>
<wsdl:part name="second" type="xsd:int"/>
</wsdl:message><wsdl:portType name="CalculatorPortType"><wsdl:operation name="add" parameterOrder="first second">
<wsdl:input message="tns:addRequest"/>
<wsdl:output message="tns:addResponse"/>
</wsdl:operation><wsdl:operation name="sub" parameterOrder="first second">
<wsdl:input message="tns:subRequest"/>
<wsdl:output message="tns:subResponse"/>
</wsdl:operation>
</wsdl:portType><wsdl:binding name="CalculatorSoapBinding" type="tns:CalculatorPortType">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="add">
<wsdlsoap:operation soapAction="add"/><wsdl:input>
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/>
</wsdl:input><wsdl:output>
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/Grimm/services/Calculator" use="encoded"/>
</wsdl:output>
</wsdl:operation><wsdl:operation name="sub">
<wsdlsoap:operation soapAction="sub"/><wsdl:input>
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/>
</wsdl:input><wsdl:output>
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/Grimm/services/Calculator" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding><wsdl:service name="CalculatorService"><wsdl:port binding="tns:CalculatorSoapBinding" name="CalculatorPort">
<wsdlsoap:address location="http://localhost/Grimm/services/Calculator"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

Installing

  1. Download the grimm ZIP
  2. Unzip the archive, and copy the Grimm directory to your web server
  3. Edit /Grimm/index.php, and change the value of BASEURL to the URL where Grimm is installed, i.e. http://mysite.com/Grimm
  4. Test the installation by opening your browser, and visiting the URL http://mysite.com/Grimm/services/Products?wsdl
  5. If you see the WSDL document for the Products services, then everything is installed and ready to go

Bugs

This is a very early release of Grimm. I already know it has some bugs. If you find one, just drop me a line in the comments here, and I’ll try to fix it.

Creating a Service

Begin by creating the file /Grimm/services/Adder.pws. All services end with the .pws (short for PHP Web Service) extension. Open the new file, and add the following PHP code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class Adder
{
	/**
	 * Adds two numbers
	 *
	 * @param int $first The first number
	 * @param int $second The second number
	 * @return int
	 */
	public function add($first, $second)
	{
		return $first + $second;
	}
}

Notice that the name of the file, and the name of the class are the same. This is required.
You can test that your new service is installed correctly by visiting the URL http://mysite.com/Grimm/services/Adder?wsdl. You should see the WSDL document for the service.

Testing the Service

You can test the service by using PHP’s SoapClient class. To do so, create a new script named adder_test.php, and save it somewhere on your web server (not in the Grimm directory hierarchy). Add the following code to the script:

1
2
3
4
5
6
7
8
9
10
<?php
$client = new SoapClient('http://mysite.com/Grimm/services/Adder?wsdl');
$first = 24;
$second = 44;
try {
	$sum = $client->add($first, $second);
	echo "The sum of the number $first, and $second is $sum";
} catch (Exception $e) {
	echo 'Error: ' $e->getMessage();
}

Then run the script in your browser by calling the script with the URL http://mysite.com/adder_test.php (or whatever URL it’s installed at). You should see the output:

The sum of the number 24, and 44 is 68

Doc Comments

SOAP/WSDL is strongly typed, and PHP is weakly typed. That means SOAP/WSDL must know what types are passed to service methods, and returned by service methods, but PHP does not provide this information. We get around this limitation by using doc comments. Take this public method as an example:

1
2
3
4
5
6
7
8
9
10
11
	/**
	 * Adds two numbers
	 *
	 * @param int $first The first number
	 * @param int $second The second number
	 * @return int
	 */
	public function add($first, $second)
	{
		return $first + $second;
	}

The doc comment above the method tells Grimm that the method takes two parameters, each one of them an integer. It also tells Grimm that the method returns an integer.

These doc comments are required!
Without the doc comments, Grimm won’t be able to generate a WSDL document for the service. The doc comments don’t have to have parameter types, but at the very least each one must have a return value.

Public properties that you wish to expose in class must also have doc comments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class MyType
{
	/**
	 * The user's name
	 *
	 * @var string
	 */
	public $name;
 
	/**
	 * The user's age
	 *
	 * @var int
	 */
	public $age;
}

The types supported by Grimm are; string, float, int, bool, object, and array.

Arrays

Grimm supports arrays of types as method parameters, return types, and property types. You can specify that a type is an array by using [] in the doc comment. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class MyType
{
	/**
	 * The user's name
	 *
	 * @var string[]
	 */
	public $names;
 
	/**
	 * The user's age
	 *
	 * @var int[]
	 */
	public $ages;
}

Notice the user of string[] and int[]. That specifies that the types are an array of strings, and an array of integers.

Custom Types

Of course web services wouldn’t be that useful if the only types you could use were the ones listed above. You can create your own custom types by creating PHP classes with public properties. Here is a service that returns user information. We’ll create a custom type as the return value for the service:

File: Grimm/services/UserScripts/UserInfo.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class UserInfo
{
	/**
	 * The user's name
	 *
	 * @var string
	 */
	public $name;
 
	/**
	 * The user's age
	 *
	 * @var int
	 */
	public $age;
 
	/**
	 * The user's email address
	 *
	 * @var string
	 */
	public $email;
}

File: Grimm/services/Users.pws

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
require_once('UserScripts/UserInfo.php');
class Users
{
	/**
	 * Returns user information
	 *
	 * @param int $user_id The user ID
	 * @return UserInfo
	 */
	public function getUser($user_id)
	{
		$user = new UserInfo();
		$user->name = 'John Doe';
		$user->age = 24;
		$user->email = 'john.doe@gmail.com';
 
		return $user;
	}
}

Notice that we specify UserInfo as the return type for getUser. Also notice we include the UserInfo.php script at the top of our service class. Grimm must be able to find the UserInfo class, and this is a good way to do it.

You can of course include custom types inside of other custom types, as in this example:

File: Grimm/services/UserFiles/UserAddress.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class UserAddress
{
	/**
	 * @var string
	 */
	public $street;
 
	/**
	 * @var string
	 */
	public $city;
 
	/**
	 * @var string
	 */
	public $state;
 
	/**
	 * @var string
	 */
	public $zip;
}

File: Grimm/services/UserFiles/UserInfo.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
require_once('UserAddress.php');
class UserInfo
{
	/**
	 * @var string
	 */
	public $name;
 
	/**
	 * @var int
	 */
	public $age;
 
	/**
	 * @var string
	 */
	public $email;
 
	/**
	 * @var UserAddress
	 */
	public $address;
}

File: Grimm/services/Users.pws

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
require_once('UserFiles/UserInfo.php');
class Users
{
	/**
	 * Returns user information
	 *
	 * @param int $user_id The user ID
	 * @return UserInfo
	 */
	public function getUser($user_id)
	{
		$user = new UserInfo();
		$user->name = 'John Doe';
		$user->age = 24;
		$user->email = 'john.doe@gmail.com';
		$user->address = new UserAddress();
		$user->address->street = '123 Elm St.';
		$user->address->city = 'Smallville';
		$user->address->state = 'PA';
		$user->address->zip = '12345';
 
		return $user;
	}
}

URL Rewiting

Grimm includes an .htaccess file that sets up URL rewriting so your services can be called using URLs like http://mysite.com/Grimm/services/Calculator?wsdl. You should delete this file if your web server does not support URL rewriting. You can then call your web services using a URL like http://mysite.com/Grimm/index.php/services/Calculator?wsdl.