Skip to content

Commit 40b40a0

Browse files
Merge pull request #49 from dapr/add/docs
2 parents 1adfb9d + 8992eca commit 40b40a0

File tree

9 files changed

+1058
-0
lines changed

9 files changed

+1058
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
---
2+
type: docs
3+
title: "Dapr PHP SDK"
4+
linkTitle: "PHP"
5+
weight: 1000
6+
description: PHP SDK packages for developing Dapr applications
7+
no_list: true
8+
---
9+
10+
Dapr offers an SDK to help with the development of PHP applications. Using it, you can create PHP clients, servers, and virtual actors with Dapr.
11+
12+
## Setting up
13+
14+
### Prerequisites
15+
16+
- [Composer](https://getcomposer.org/)
17+
- [PHP 8](https://www.php.net/)
18+
19+
### Optional Prerequisites
20+
21+
- [Docker](https://www.docker.com/)
22+
- [xdebug](http://xdebug.org/) -- for debugging
23+
24+
## Initialize your project
25+
26+
In a directory where you want to create your service, run `composer init` and answer the questions.
27+
Install `dapr/php-sdk` and any other dependencies you may wish to use.
28+
29+
## Configure your service
30+
31+
Create a config.php, copying the contents below:
32+
33+
```php
34+
<?php
35+
36+
use Dapr\Actors\Generators\ProxyFactory;
37+
use function DI\env;
38+
39+
return [
40+
// Generate a new proxy on each request - recommended for development
41+
'dapr.actors.proxy.generation' => ProxyFactory::GENERATED,
42+
43+
// put any subscriptions here
44+
'dapr.subscriptions' => [],
45+
46+
// if this service will be hosting any actors, add them here
47+
'dapr.actors' => [],
48+
49+
// if this service will be hosting any actors, configure how long until dapr should consider an actor idle
50+
'dapr.actors.idle_timeout' => null,
51+
52+
// if this service will be hosting any actors, configure how often dapr will check for idle actors
53+
'dapr.actors.scan_interval' => null,
54+
55+
// if this service will be hosting any actors, configure how long dapr will wait for an actor to finish during drains
56+
'dapr.actors.drain_timeout' => null,
57+
58+
// if this service will be hosting any actors, configure if dapr should wait for an actor to finish
59+
'dapr.actors.drain_enabled' => null,
60+
61+
// you shouldn't have to change this, but the setting is here if you need to
62+
'dapr.port' => env('DAPR_HTTP_PORT', '3500'),
63+
64+
// add any custom serialization routines here
65+
'dapr.serializers.custom' => [],
66+
67+
// add any custom deserialization routines here
68+
'dapr.deserializers.custom' => [],
69+
];
70+
```
71+
72+
## Create your service
73+
74+
Create `index.php` and put the following contents:
75+
76+
```php
77+
<?php
78+
79+
require_once __DIR__.'/vendor/autoload.php';
80+
81+
use Dapr\App;
82+
83+
$app = App::create(configure: fn(\DI\ContainerBuilder $builder) => $builder->addDefinitions(__DIR__ . '/config.php'));
84+
$app->get('/hello/{name}', function(string $name) {
85+
return ['hello' => $name];
86+
});
87+
$app->start();
88+
```
89+
90+
## Try it out
91+
92+
Initialize dapr with `dapr init` and then start the project with `dapr run -a dev -p 3000 -- php -S 0.0.0.0:3000`.
93+
94+
You can now open a web browser and point it to [http://localhost:3000/hello/world](http://localhost:3000/hello/world)
95+
replacing `world` with your name, a pet's name, or whatever you want.
96+
97+
Congratulations, you've created your first Dapr service! I'm excited to see what you'll do with it!
98+
99+
## More Information
100+
101+
- [Packagist](https://packagist.org/packages/dapr/php-sdk)
102+
- [Dapr SDK serialization]({{< ref sdk-serialization.md >}})
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
---
2+
type: docs
3+
title: "Virtual Actors"
4+
linkTitle: "Actors"
5+
weight: 1000
6+
description: How to build actors
7+
no_list: true
8+
---
9+
10+
If you're new to the actor pattern, the best place to learn about the actor pattern is in
11+
the [Actor Overview.]({{< ref actors-overview.md >}})
12+
13+
In the PHP SDK, there are two sides to an actor, the Client, and the Actor (aka, the Runtime). As a client of an actor,
14+
you'll interact with a remote actor via the `ActorProxy` class. This class generates a proxy class on-the-fly using one
15+
of several configured strategies.
16+
17+
When writing an actor, state can be managed for you. You can hook into the actor lifecycle, and define reminders and
18+
timers. This gives you considerable power for handling all types of problems that the actor pattern is suited for.
19+
20+
## The Actor Proxy
21+
22+
Whenever you want to communicate with an actor, you'll need to get a proxy object to do so. The proxy is responsible for
23+
serializing your request, deserializing the response, and returning it to you, all while obeying the contract defined by
24+
the specified interface.
25+
26+
In order to create the proxy, you'll first need an interface to define how and what you send and receive from an actor.
27+
For example, if you want to communicate with a counting actor that solely keeps track of counts, you might define the
28+
interface as follows:
29+
30+
```php
31+
#[\Dapr\Actors\Attributes\DaprType('Counter')]
32+
interface ICount {
33+
function increment(int $amount = 1): void;
34+
function get_count(): int;
35+
}
36+
```
37+
38+
It's a good idea to put this interface in a shared library that the actor and clients can both access (if both are written in PHP). The `DaprType`
39+
attribute tells the DaprClient the name of the actor to send to. It should match the implementation's `DaprType`, though
40+
you can override the type if needed.
41+
42+
```php
43+
$app->run(function(\Dapr\Actors\ActorProxy $actorProxy) {
44+
$actor = $actorProxy->get(ICount::class, 'actor-id');
45+
$actor->increment(10);
46+
});
47+
```
48+
49+
## Writing Actors
50+
51+
To create an actor, you need to implement the interface you defined earlier and also add the `DaprType` attribute. All
52+
actors *must* implement `IActor`, however there's an `Actor` base class that implements the boilerplate making your
53+
implementation much simpler.
54+
55+
Here's the counter actor:
56+
57+
```php
58+
#[\Dapr\Actors\Attributes\DaprType('Count')]
59+
class Counter extends \Dapr\Actors\Actor implements ICount {
60+
function __construct(string $id, private CountState $state) {
61+
parent::__construct($id);
62+
}
63+
64+
function increment(int $amount = 1): void {
65+
$this->state->count += $amount;
66+
}
67+
68+
function get_count(): int {
69+
return $this->state->count;
70+
}
71+
}
72+
```
73+
74+
The most important bit is the constructor. It takes at least one argument with the name of `id` which is the id of the
75+
actor. Any additional arguments are injected by the DI container, including any `ActorState` you want to use.
76+
77+
### Actor Lifecycle
78+
79+
An actor is instantiated via the constructor on every request targeting that actor type. You can use it to calculate
80+
ephemeral state or handle any kind of request-specific startup you require, such as setting up other clients or
81+
connections.
82+
83+
After the actor is instantiated, the `on_activation()` method may be called. The `on_activation()` method is called any
84+
time the actor "wakes up" or when it is created for the first time. It is not called on every request.
85+
86+
Next, the actor method is called. This may be from a timer, reminder, or from a client. You may perform any work that
87+
needs to be done and/or throw an exception.
88+
89+
Finally, the result of the work is returned to the caller. After some time (depending on how you've configured the
90+
service), the actor will be deactivated and `on_deactivation()` will be called. This may not be called if the host dies,
91+
daprd crashes, or some other error occurs which prevents it from being called successfully.
92+
93+
## Actor State
94+
95+
Actor state is a "Plain Old PHP Object" (POPO) that extends `ActorState`. The `ActorState` base class provides a couple
96+
of useful methods. Here's an example implementation:
97+
98+
```php
99+
class CountState extends \Dapr\Actors\ActorState {
100+
public int $count = 0;
101+
}
102+
```
103+
104+
## Registering an Actor
105+
106+
Dapr expects to know what actors a service may host at startup. You need to add it to the configuration:
107+
108+
{{< tabs "Production" "Development" >}}
109+
110+
{{% codetab %}}
111+
112+
If you want to take advantage of pre-compiled dependency injection, you need to use a factory:
113+
114+
```php
115+
<?php
116+
// in config.php
117+
118+
return [
119+
'dapr.actors' => fn() => [Counter::class],
120+
];
121+
```
122+
123+
All that is required to start the app:
124+
125+
```php
126+
<?php
127+
128+
require_once __DIR__ . '/vendor/autoload.php';
129+
130+
$app = \Dapr\App::create(
131+
configure: fn(\DI\ContainerBuilder $builder) => $builder->addDefinitions('config.php')->enableCompilation(__DIR__)
132+
);
133+
$app->start();
134+
```
135+
136+
{{% /codetab %}}
137+
{{% codetab %}}
138+
139+
```php
140+
<?php
141+
// in config.php
142+
143+
return [
144+
'dapr.actors' => [Counter::class]
145+
];
146+
```
147+
148+
All that is required to start the app:
149+
150+
```php
151+
<?php
152+
153+
require_once __DIR__ . '/vendor/autoload.php';
154+
155+
$app = \Dapr\App::create(configure: fn(\DI\ContainerBuilder $builder) => $builder->addDefinitions('config.php'));
156+
$app->start();
157+
```
158+
159+
{{% /codetab %}}
160+
{{< /tabs >}}

0 commit comments

Comments
 (0)