GeniusesOfSymfony / WebSocketBundle

:part_alternation_mark: Websocket server for Symfony applications (powered by Ratchet), includes a Autobahn.JS based JavaScript client
MIT License
609 stars 140 forks source link

push in version 2 #378

Closed vittore closed 5 years ago

vittore commented 5 years ago

Hi,

I'm using symfony 3.4 (with flex) and autowire; in composer.json I have:

"gos/web-socket-bundle": "dev-master",

so version 2 is used.

Now I have a command (extends ContainerAwareCommand) that it will send a message:

protected function execute(InputInterface $input, OutputInterface $output)
    {
        $pusher=$this->getContainer()->get('gos_web_socket.wamp.pusher');
        $pushMessage['text']=$input->getOption('message');

        $pusher->push($pushMessage, 'system_message');
    }

But i get the error:

 The "gos_web_socket.wamp.pusher" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and   use dependency injection instead.

Is there an example for push with version 2?

Thanks in advance. v

mbabker commented 5 years ago

I'd suggest not extending ContainerAwareCommand since that is deprecated and injecting the pusher as a dependency (either as a constructor argument or a setPusher(PusherInterface $pusher) call. If it's too painful we can add public: true onto the pusher service definitions but personally I think the scope of what's considered a public service by the bundle should be kept to a minimum (I did do a pass to explicitly mark things public/private, it looks like the pushers are inheriting the public:false set on the abstract pusher definition as a result).

The other option is you can use a compiler pass in your own application to make the service public if you really need to but this kind of $this->container->get() stuff is really not the encouraged practice anymore, it's preferred to use explicit dependency injection instead.

vittore commented 5 years ago

Uhm.... something goes wrong. I done:


namespace App\Command;

use Gos\Bundle\WebSocketBundle\Pusher\PusherInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SendMessageCommand extends Command
{
    private $pusher;

    public function __construct(PusherInterface $pusher)
    {
        $this->pusher=$pusher;
        parent::__construct();
    }

    protected function configure()
    {
        $this->setName('send-socket:message')
            ->setDescription('Send message')
            ->addOption(
                'user',
                null,
                InputOption::VALUE_REQUIRED,
                'user',
                ''
            )
            ->addOption(
                'message',
                null,
                InputOption::VALUE_REQUIRED,
                'message',
                ''
            );
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $pushMessage['text']=$input->getOption('message');
        $pushMessage['to'] =strtolower($input->getOption('user'));

        $this->pusher->push($pushMessage, 'you4b_message');
    }
}

But when run I get:

In DefinitionErrorExceptionPass.php line 37:

  Cannot autowire service "App\Command\SendMessageCommand": argument "$pusher" of method "__construct()" references interface "Gos\Bundle\WebSocketBundle\Pusher\PusherInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "gos_web_socket.wamp.pusher.data_collector", "gos_web_socket.wamp.pusher.data_collector.inner".

What is correct definition for this service?

Thanks. v.

mbabker commented 5 years ago

You have to manually specify the $pusher argument to get the correct pusher. The PusherInterface isn't aliased to anything since by default all of the pusher services are available as services and stripped out if they aren't enabled, so you can't autowire the pushers unfortunately. Here's an example service definition I use:

    App\EventListener\BroadcastResourceCreatedListener:
        tags:
            - { name: kernel.event_listener, event: app.resource_created, method: onResourceCreated }
            - { name: monolog.logger, channel: app }
        arguments:
            '$pusher': '@gos_web_socket.wamp.pusher'

Also, make sure you typehint the interface because when the kernel is in debug mode (i.e. dev environment) the pushers are decorated so if you typehinted Gos\Bundle\WebSocketBundle\Pusher\Wamp\WampPusher instead of Gos\Bundle\WebSocketBundle\Pusher\PusherInterface you'll run into problems because the decorating Gos\Bundle\WebSocketBundle\DataCollector\PusherDecorator class is used.

vittore commented 5 years ago

Sorry but I don't undestand. I do this in services.yml:

services:
  App\Command\SendMessageCommand:
        arguments:
          '$pusher': '@gos_web_socket.wamp.pusher'

And this in command definition:

<?php

namespace App\Command;

use Gos\Bundle\WebSocketBundle\Pusher\PusherInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SendMessageCommand extends Command
{
    private $pusher;

    public function __construct(PusherInterface $pusher)
    {
        $this->pusher=$pusher;
        parent::__construct();
    }

    protected function configure()
    {
        $this->setName('send-socket:message')
            ->setDescription('Send message')
            ->addOption(
                'user',
                null,
                InputOption::VALUE_REQUIRED,
                'user',
                ''
            )
            ->addOption(
                'message',
                null,
                InputOption::VALUE_REQUIRED,
                'message',
                ''
            );
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $pushMessage['text']=$input->getOption('message');
        $pushMessage['to'] =strtolower($input->getOption('user'));

        $this->pusher->push($pushMessage, 'you4b_message');
    }
}

But I get this error:

php bin/console send-socket:message --user user1-it --message caio

[WARNING] Some commands could not be registered:
In MessageSerializer.php line 35:
  Class 'Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer' not found
  There are no commands defined in the "send-socket" namespace.

I "simply" want to send a push message to a specific user via php bin/console command. Sigh. :(

v.

mbabker commented 5 years ago

In MessageSerializer.php line 35: Class 'Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer' not found

You need to composer require symfony/serializer as indicated in the "suggest" section of the Composer install. That will probably fix your issue with the command not being registered since its dependencies aren't all being resolved correctly.

vittore commented 5 years ago

It's works.

Thanks a lot. v.