Topic route parameters
Declaring a single websocket topic with Sandstone is like:
$app->topic('chat/general', function ($topicPattern) {
return new ChatTopic($topicPattern);
});
Note:
$app
is your Sandstone application instance, created with$app = new Eole\Sandstone\Application()
.See Full example of Sandstone application to have an example to how to bootstrap a Sandstone application.
With the following ChatTopic
class:
class ChatTopic extends Eole\Sandstone\Websocket\Topic
{
// Where you can implement chat topic logic
public function onPublish(Ratchet\Wamp\WampConnection $conn, $topic, $event) {}
public function onSubscribe(Ratchet\Wamp\WampConnection $conn, $topic) {}
public function onUnSubscribe(Ratchet\Wamp\WampConnection $conn, $topic) {}
}
See Example of Chat server to have a full exemple of this
ChatTopic
.
Adding arguments in topic route
You may need to declare multiple chat topics,
i.e chat/series
, chat/manga
, chat/gaming
, chat/actu
, …
So you have to make the topic name dynamic, with chat/{channel}
:
$app->topic('chat/{channel}', function ($topicPattern) {
return new ChatTopic($topicPattern);
});
With this example, you can use the same ChatTopic
class
for every topic subscribed by JavaScript clients.
Sandstone will implement multiple topic instances of this same class
everytime someone subscribes or publish to a new chat/{channel}
which has not yet been used.
Then, when someone subscribes and/or publish on a new chat topic,
i.e chat/my-new-topic
, Sandstone will instanciate a new websocket topic
from the ChatTopic
(because chat/my-new-topic
matches chat/{channel}
)
with my-new-topic
as route argument.
Retrieve topic route arguments
Let’s admit someone subscribes for the first time to chat/my-new-topic
topic.
Sandstone will create a new instance of ChatTopic
.
You may need to access to topic arguments, here "my-new-topic"
,
in you ChatTopic
.
Here is how to to do it: Sandstone passes route arguments in your topic callback as an array, in a second argument.
So just retrieve the channel name in this array and pass it to your ChatTopic
constructor:
$app->topic('chat/{channel}', function ($topicPattern, $arguments) {
$channel = $arguments['channel'];
return new ChatTopic($topicPattern, $channel);
});
Then, in your ChatTopic
constructor:
class ChatTopic extends Eole\Sandstone\Websocket\Topic
{
/**
* @var string
*/
private $channel;
/**
* @param string $topicPath
* @param string $channel
*/
public function __construct($topicPath, $channel)
{
parent::__construct($topicPath);
$this->channel = $channel;
}
}
You now have access to the $channel
argument used in topic route chat/{channel}
.
You can by example greeting new subscribers:
public function onSubscribe(Ratchet\Wamp\WampConnection $conn, $topic)
{
parent::onSubscribe($conn, $topic);
// Greeting new subscriber.
$conn->event([
'type' => 'greet',
'message' => 'Hello, welcome on '.$this->channel',
]);
// Broadcast everyone that someone joined the channel
$this->broadcast([
'type' => 'join',
'message' => 'Someone has joined this channel.',
]);
}
Add constraints on route parameters
Declaring a topic route is the same as declaring an http route.
Note: See Silex documentation about route configuration: Routing Global Configuration
So you can add constraints, by example:
- Regex: allow only number for id
$app
->topic('games/{id}/moves-played', function ($topicPattern, $arguments) {
return new GameTopic($topicPattern, $arguments['id']);
})
->assert('id', '\d+')
;
- Regex: limit only some argument values
$app
->topic('chat/{channel}', function ($topicPattern, $arguments) {
return new ChatTopic($topicPattern, $arguments['channel']);
})
->assert('channel', '^(general|series|manga|gaming|actu)$')
;
- Make argument optional and add a default value
$app
->topic('chat/{channel}', function ($topicPattern, $arguments) {
return new ChatTopic($topicPattern, $arguments['channel']);
})
->value('channel', 'general')
;
- Using multiple rules at same time
$app
->topic('chat/{channel}', function ($topicPattern, $arguments) {
return new ChatTopic($topicPattern, $arguments['channel']);
})
->assert('channel', '^(general|series|manga|gaming|actu)$')
->value('channel', 'general')
;