diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index e5fd8fd9fde7..6b71b34cfb76 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -30,10 +30,10 @@ abstract class Broadcaster implements BroadcasterContract * Register a channel authenticator. * * @param string $channel - * @param callable $callback + * @param callable|string $callback * @return $this */ - public function channel($channel, callable $callback) + public function channel($channel, $callback) { $this->channels[$channel] = $callback; @@ -56,8 +56,9 @@ protected function verifyUserCanAccessChannel($request, $channel) } $parameters = $this->extractAuthParameters($pattern, $channel, $callback); + $handler = $this->normalizeChannelHandlerToCallable($callback); - if ($result = $callback($request->user(), ...$parameters)) { + if ($result = $handler($request->user(), ...$parameters)) { return $this->validAuthenticationResponse($request, $result); } } @@ -75,7 +76,7 @@ protected function verifyUserCanAccessChannel($request, $channel) */ protected function extractAuthParameters($pattern, $channel, $callback) { - $callbackParameters = (new ReflectionFunction($callback))->getParameters(); + $callbackParameters = $this->extractParameters($callback); return collect($this->extractChannelKeys($pattern, $channel))->reject(function ($value, $key) { return is_numeric($key); @@ -84,6 +85,28 @@ protected function extractAuthParameters($pattern, $channel, $callback) })->values()->all(); } + /** + * Extracts the parameters out of what the user passed to handle the channel authentication. + * + * @param callable|string $callback + * @return \ReflectionParameter[] + * @throws \Exception + */ + protected function extractParameters($callback) + { + if (is_callable($callback)) { + return (new ReflectionFunction($callback))->getParameters(); + } + + if (is_string($callback)) { + return (new \ReflectionClass($callback)) + ->getMethod('join') + ->getParameters(); + } + + throw new \Exception('Unknown channel handler type.'); + } + /** * Extract the channel keys from the incoming channel name. * @@ -201,4 +224,19 @@ protected function binder() return $this->bindingRegistrar; } + + /** + * @param $callback + * @return callable|\Closure + */ + protected function normalizeChannelHandlerToCallable($callback) + { + return is_callable($callback) + ? $callback + : function (...$args) use ($callback) { + return Container::getInstance() + ->make($callback) + ->join(...$args); + }; + } } diff --git a/src/Illuminate/Foundation/Console/ChannelMakeCommand.php b/src/Illuminate/Foundation/Console/ChannelMakeCommand.php new file mode 100644 index 000000000000..7a539a21f7f2 --- /dev/null +++ b/src/Illuminate/Foundation/Console/ChannelMakeCommand.php @@ -0,0 +1,50 @@ + 'command.app.name', 'AuthMake' => 'command.auth.make', 'CacheTable' => 'command.cache.table', + 'ChannelMake' => 'command.channel.make', 'ConsoleMake' => 'command.console.make', 'ControllerMake' => 'command.controller.make', 'EventGenerate' => 'command.event.generate', @@ -400,6 +402,18 @@ protected function registerJobMakeCommand() }); } + /** + * Register the command. + * + * @return void + */ + protected function registerChannelMakeCommand() + { + $this->app->singleton('command.channel.make', function ($app) { + return new ChannelMakeCommand($app['files']); + }); + } + /** * Register the command. * diff --git a/tests/Broadcasting/BroadcasterTest.php b/tests/Broadcasting/BroadcasterTest.php index 66448db8b7d2..c1364ad40f05 100644 --- a/tests/Broadcasting/BroadcasterTest.php +++ b/tests/Broadcasting/BroadcasterTest.php @@ -57,6 +57,34 @@ public function testExtractingParametersWhileCheckingForUserAccess() Container::setInstance(new Container); } + public function testCanUseChannelClasses() + { + $broadcaster = new FakeBroadcaster; + + $parameters = $broadcaster->extractAuthParameters('asd.{model}.{nonModel}', 'asd.1.something', DummyBroadcastingChannel::class); + $this->assertEquals(['model.1.instance', 'something'], $parameters); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Unknown channel handler type. + */ + public function testUnknownChannelAuthHandlerTypeThrowsException() + { + $broadcaster = new FakeBroadcaster; + + $broadcaster->extractAuthParameters('asd.{model}.{nonModel}', 'asd.1.something', 123); + } + + public function testCanRegisterChannelsAsClasses() + { + $broadcaster = new FakeBroadcaster; + + $broadcaster->channel('something', function () { + }); + $broadcaster->channel('somethingelse', DummyBroadcastingChannel::class); + } + /** * @expectedException \Symfony\Component\HttpKernel\Exception\HttpException * @expectedExceptionMessage @@ -129,3 +157,11 @@ public function first() // } } + +class DummyBroadcastingChannel +{ + public function join($user, BroadcasterTestEloquentModelStub $model, $nonModel) + { + // + } +}