| Q | A
| ---------------- | -----
| Bug report? |no
| Feature request? | yes
| BC Break report? |no
| RFC? | no
| Version/Branch | x.y.z
is there a possibility to add subscription type to the bundle or make another compatible bundle like the data loader
i think this would be possible with a library like ratchet
they already discussed the issue in webonyx
https://github.com/webonyx/graphql-php/issues/9
webonyx/graphql-php is the best place to debate about this, the bundle is just the symfony implementation. This feature is requiring a direct implementation in the main lib... Maybe using this https://siler.leocavalcante.com/graphql/subscriptions.html could also helps...
feel free to reopen if needed...
sorry for reopening this issue after a long time, i decided to implement subscription on top of your bundle, siler's example works when you create a symfony command that runs ratchet on a different port, i can pass the schema to the websocket server, however subscription resolvers need to take the payload in the function argument instead of the query variables, and i found some difficulties to add a new type of resolvers to your bundle,
@omarsoufiane can you provide some snippets of the issue please ?
first graphiql and react needs a higher default version on the config
and subscription types work by default
`overblog_graphql:
versions:
graphiql: 0.9.3
react: 15.4.2
definitions:
schema:
query: Query
mutation: Mutation
subscription: Subscription`
you need a class with a subscribe and publish method that we will register as a service to use it in the sumfony command and mutation resolver
`use GraphQL\Schema;
use Ratchet\Client;
use Ratchet\Client\WebSocket;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
const INIT = 'init';
const INIT_SUCCESS = 'init_success';
const INIT_FAIL = 'init_fail';
const SUBSCRIPTION_START = 'subscription_start';
const SUBSCRIPTION_END = 'subscription_end';
const SUBSCRIPTION_SUCCESS = 'subscription_success';
const SUBSCRIPTION_FAIL = 'subscription_fail';
const SUBSCRIPTION_DATA = 'subscription_data';
class Subscription
{
protected $host;
protected $port;
/**
* SubscriptionCommand constructor.
* @param $host
* @param $port
*/
public function __construct($host, $port)
{
$this->host = $host;
$this->port = $port;
}
/**
* Returns a new websocket server bootstraped for GraphQL subscriptions.
*
* @param Schema $schema
* @param array $filters
* @param array $rootValue
* @param array $context
* @param int $port
* @param string $host
* @return IoServer
*/
function subscribe(
Schema $schema,
array $filters = null,
array $rootValue = null,
array $context = null,
$port = 7070,
$host = '0.0.0.0'
) {
$manager = new SubscriptionManager($schema, $filters, $rootValue, $context);
$server = new SubscriptionServer($manager);
$websocket = new WsServer($server);
$websocket->disableVersion(0);
$http = new HttpServer($websocket);
return IoServer::factory($http, $port, $host);
}
/**
* Publishes the given $payload to the $subscribeName.
*
* @param string $subscriptionName
* @param mixed $payload
*/
function publish($subscriptionName, $payload = null)
{
Client\connect('ws://127.0.0.1:7070')->then(function (WebSocket $conn) use ($subscriptionName, $payload) {
$request = [
'type' => SUBSCRIPTION_DATA,
'subscription' => $subscriptionName,
'payload' => $payload,
];
$conn->send(json_encode($request));
$conn->close();
});
}
}`
then create a command that runs the websocket server on a different port
`class SubscriptionCommand extends ContainerAwareCommand
{
/**
* Configure a new Command Line
*/
protected function configure()
{
$this
->setName('graphql:subscription:server')
->setDescription('Start the notification server.')
->addOption(
'file',
null,
InputOption::VALUE_OPTIONAL,
'Path to generate schema file.'
)
->addOption(
'schema',
null,
InputOption::VALUE_OPTIONAL,
'The schema name to generate.'
)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output = new SymfonyStyle($input, $output);
$container = $this->getContainer();
//the problem is here i guess, the schema already has resolvers and they don't accept payloads as //function argument
$schema = $container
->get('overblog_graphql.request_executor')
->getSchema();
//filters is a way to know which subscription should recieve data after you send a mutation as explained in siler
$filters = [
'inbox' => function ($payload, $vars) {
return ($payload['roomid'] == $vars['roomid']) ;
},
];
$subscription = $container->get('subscription_command');
$subscription->subscribe($schema, $filters)->run();
}
}`
subscription server and subscription manager are two files i got from siler:
https://github.com/leocavalcante/siler/tree/master/src/Graphql
since they rely on a function specific to the framework yo need to add it
` /*
* array get function imported from sliler root
*/
public function array_get($array, $key = null, $default = null)
{
if (is_null($key)) {
return $array;
}
return array_key_exists($key, $array) ? $array[$key] : $default;
}`
thank you for the example. I don't have a lot of time to work on that right now but hope to get a look more carefully on this before the weekend...
Most helpful comment
subscription server and subscription manager are two files i got from siler:
https://github.com/leocavalcante/siler/tree/master/src/Graphql
since they rely on a function specific to the framework yo need to add it
` /*
* array get function imported from sliler root
*/