From 0079fc84c3fb7dd7d32b90e2f42cd5f463081c6b Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Sun, 31 Dec 2017 13:37:15 -0300 Subject: [PATCH 1/4] Allow registering channel authentication handlers as classes --- .../Broadcasting/Broadcasters/Broadcaster.php | 46 +++++++++++++++++-- tests/Broadcasting/BroadcasterTest.php | 35 ++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) 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/tests/Broadcasting/BroadcasterTest.php b/tests/Broadcasting/BroadcasterTest.php index 66448db8b7d2..eb4f7a6ab885 100644 --- a/tests/Broadcasting/BroadcasterTest.php +++ b/tests/Broadcasting/BroadcasterTest.php @@ -57,6 +57,33 @@ 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 +156,11 @@ public function first() // } } + +class DummyBroadcastingChannel +{ + public function join($user, BroadcasterTestEloquentModelStub $model, $nonModel) + { + + } +} From d8d29ae7863dd406de2468460fd3377021db4377 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Sun, 31 Dec 2017 13:44:43 -0300 Subject: [PATCH 2/4] Add Artisan command to generate the channels authentication classes --- .../Foundation/Console/ChannelMakeCommand.php | 51 +++++++++++++++++++ .../Foundation/Console/stubs/channel.stub | 26 ++++++++++ .../Providers/ArtisanServiceProvider.php | 14 +++++ 3 files changed, 91 insertions(+) create mode 100644 src/Illuminate/Foundation/Console/ChannelMakeCommand.php create mode 100644 src/Illuminate/Foundation/Console/stubs/channel.stub diff --git a/src/Illuminate/Foundation/Console/ChannelMakeCommand.php b/src/Illuminate/Foundation/Console/ChannelMakeCommand.php new file mode 100644 index 000000000000..73b9e66c196a --- /dev/null +++ b/src/Illuminate/Foundation/Console/ChannelMakeCommand.php @@ -0,0 +1,51 @@ + '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. * From 02d3a0d583eef4bcec3b1150bb072b722a6c689a Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Sun, 31 Dec 2017 14:15:40 -0300 Subject: [PATCH 3/4] Remove unused use statements --- src/Illuminate/Foundation/Console/ChannelMakeCommand.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/ChannelMakeCommand.php b/src/Illuminate/Foundation/Console/ChannelMakeCommand.php index 73b9e66c196a..7a539a21f7f2 100644 --- a/src/Illuminate/Foundation/Console/ChannelMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ChannelMakeCommand.php @@ -3,7 +3,6 @@ namespace Illuminate\Foundation\Console; use Illuminate\Console\GeneratorCommand; -use Symfony\Component\Console\Input\InputOption; class ChannelMakeCommand extends GeneratorCommand { From 5190646601f2f9e1e3531ee8337639d41c4bd08d Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Sun, 31 Dec 2017 14:16:49 -0300 Subject: [PATCH 4/4] Linting --- tests/Broadcasting/BroadcasterTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Broadcasting/BroadcasterTest.php b/tests/Broadcasting/BroadcasterTest.php index eb4f7a6ab885..c1364ad40f05 100644 --- a/tests/Broadcasting/BroadcasterTest.php +++ b/tests/Broadcasting/BroadcasterTest.php @@ -80,7 +80,8 @@ public function testCanRegisterChannelsAsClasses() { $broadcaster = new FakeBroadcaster; - $broadcaster->channel('something', function () {}); + $broadcaster->channel('something', function () { + }); $broadcaster->channel('somethingelse', DummyBroadcastingChannel::class); } @@ -161,6 +162,6 @@ class DummyBroadcastingChannel { public function join($user, BroadcasterTestEloquentModelStub $model, $nonModel) { - + // } }