diff --git a/composer.json b/composer.json index eeeec7d..aca927c 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "ext-ctype": "*", "ext-iconv": "*", "guzzlehttp/guzzle": "^6.3", + "josephlavin/tap": "^1.0", "symfony/cache": "4.2.*", "symfony/console": "4.2.*", "symfony/dotenv": "4.2.*", diff --git a/composer.lock b/composer.lock index dc0a09e..4340eea 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "15c99cfaa96233a5a12cf632ac267c27", + "content-hash": "35f8b30095e57576a83ae4bdaa898a19", "packages": [ { "name": "guzzlehttp/guzzle", @@ -189,6 +189,45 @@ ], "time": "2018-12-04T20:46:45+00:00" }, + { + "name": "josephlavin/tap", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/josephlavin/tap.git", + "reference": "8733d96fb9b7d7dca204dfe59ec3ff34f3c69be9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/josephlavin/tap/zipball/8733d96fb9b7d7dca204dfe59ec3ff34f3c69be9", + "reference": "8733d96fb9b7d7dca204dfe59ec3ff34f3c69be9", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "~5.7" + }, + "type": "library", + "autoload": { + "files": [ + "src/tap.php", + "src/TapProxy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Stand alone port of Laravel's tap method.", + "keywords": [ + "laravel", + "php", + "tap" + ], + "time": "2017-09-24T23:36:28+00:00" + }, { "name": "psr/cache", "version": "1.0.1", diff --git a/src/Command/PickWinnerCommand.php b/src/Command/PickWinnerCommand.php index 4777b34..8dce116 100644 --- a/src/Command/PickWinnerCommand.php +++ b/src/Command/PickWinnerCommand.php @@ -2,6 +2,7 @@ namespace App\Command; +use App\Service\Picker; use GuzzleHttp\Client; use Symfony\Component\Cache\Simple\FilesystemCache; use Symfony\Component\Console\Command\Command; @@ -19,10 +20,22 @@ class PickWinnerCommand extends Command */ private $client; - public function __construct() + /** + * @var \App\Service\Picker + */ + private $picker; + + /** + * PickWinnerCommand constructor. + * + * @param \App\Service\Picker $picker + * The Picker service. + */ + public function __construct(Picker $picker) { parent::__construct(); $this->client = new Client(); + $this->picker = $picker; } /** diff --git a/src/Service/Picker.php b/src/Service/Picker.php new file mode 100644 index 0000000..888b15f --- /dev/null +++ b/src/Service/Picker.php @@ -0,0 +1,113 @@ +comments = collect(); + $this->hosts = collect(); + } + + /** + * Retrieve the combined comments for all events. + * + * @return \Tightenco\Collect\Support\Collection + */ + public function getComments(): Collection + { + return $this->comments; + } + + /** + * Retrieve the event hosts. + * + * @return \Tightenco\Collect\Support\Collection + */ + public function getHosts(): Collection + { + return $this->hosts; + } + + /** + * Set the hosts for the retrieved events. + * + * @param \Tightenco\Collect\Support\Collection $data + * The event data. + * + * @return self + */ + public function setHosts(Collection $data): self + { + $this->hosts = $data->pluck('hosts.*.host_name') + ->flatten(1) + ->unique() + ->sort(); + + return $this; + } + + /** + * Set the comments for the events. + * + * @param \Tightenco\Collect\Support\Collection $comments + * A collection of comments. + * + * @return $this + */ + public function setComments(Collection $comments): self + { + $this->comments = $comments + ->flatten(1) + ->filter(function (array $comment) { + return !$this->isUserAnEventHost($comment['user_display_name']); + }) + ->values(); + + return $this; + } + + /** + * Determine whether a commenter is an event host. + * + * @param string $user_display_name + * The user's display name. + * + * @return bool + */ + private function isUserAnEventHost(string $user_display_name): bool + { + return $this->hosts->contains($user_display_name); + } + + /** + * Select and return the winners. + * + * @param int $count + * The number of winners. + * + * @return \Tightenco\Collect\Support\Collection + */ + public function getWinners(int $count): Collection + { + return $this->getComments()->random($count); + } +} diff --git a/symfony.lock b/symfony.lock index 7bb8952..f4cb6b9 100644 --- a/symfony.lock +++ b/symfony.lock @@ -14,6 +14,9 @@ "guzzlehttp/psr7": { "version": "1.5.2" }, + "josephlavin/tap": { + "version": "v1.0.0" + }, "nikic/php-parser": { "version": "v4.2.0" }, diff --git a/tests/Service/PickerTest.php b/tests/Service/PickerTest.php new file mode 100644 index 0000000..50b53c7 --- /dev/null +++ b/tests/Service/PickerTest.php @@ -0,0 +1,141 @@ + [ + ['host_name' => 'Lee Stone'], + ['host_name' => 'Dave Liddament'], + ['host_name' => 'Kat Zien'], + ], + ], + [ + 'hosts' => [ + ['host_name' => 'Oliver Davies'], + ['host_name' => 'Lee Stone'], + ['host_name' => 'Lucia Velasco'], + ['host_name' => 'Dave Liddament'], + ], + ], + ]; + + $hosts = (new Picker()) + ->setHosts(collect($data)) + ->getHosts(); + + $this->assertInstanceOf(Collection::class, $hosts); + $this->assertCount(5, $hosts); + } + + /** @test */ + public function comments_for_multiple_events_are_flattened_and_combined() + { + $data = [ + [ + [ + 'comment' => 'Great talk!', + 'user_display_name' => 'Dan Ackroyd', + ], + [ + 'comment' => 'Could be better.', + 'user_display_name' => 'Lucia Velasco', + ], + ], + [ + [ + 'comment' => 'Needs more cat pictures.', + 'user_display_name' => 'Rupert Jabelman', + ], + ], + ]; + + $comments = (new Picker()) + ->setComments(collect($data)) + ->getComments(); + + $this->assertInstanceOf(Collection::class, $comments); + $this->assertCount(3, $comments); + } + + /** @test */ + public function comments_from_event_hosts_cannot_be_picked() + { + $event = [ + 'hosts' => [ + ['host_name' => 'Oliver Davies'], + ], + ]; + + $comments = [ + [ + [ + 'comment' => 'Great talk!', + 'user_display_name' => 'Peter Fisher', + ], + [ + 'comment' => 'Text on slides could be bigger.', + 'user_display_name' => 'Oliver Davies', + ], + [ + 'comment' => 'Speak slower.', + 'user_display_name' => 'Zan Baldwin', + ], + ], + ]; + + $comments = (new Picker()) + ->setHosts(collect([$event])) + ->setComments(collect($comments)) + ->getComments(); + + $this->assertCount(2, $comments); + $this->assertSame('Peter Fisher', $comments[0]['user_display_name']); + $this->assertSame('Zan Baldwin', $comments[1]['user_display_name']); + } + + /** @test */ + public function winners_can_be_selected() + { + $comments = [ + [ + [ + 'comment' => 'Great talk!', + 'user_display_name' => 'Peter Fisher', + ], + [ + 'comment' => 'Text on slides could be bigger.', + 'user_display_name' => 'Michael Bush', + ], + [ + 'comment' => 'Speak slower.', + 'user_display_name' => 'Zan Baldwin', + ], + ], + ]; + + $picker = new Picker(); + $picker->setComments(collect($comments)); + $this->assertCount(3, $picker->getComments()); + + tap($picker->getWinners(1), function (Collection $winners) use ($picker) { + $this->assertCount(1, $winners); + $this->assertTrue($picker->getComments()->contains($winners->first())); + }); + + tap($picker->getWinners(2), function (Collection $winners) use ($picker) { + $this->assertCount(2, $winners); + $this->assertTrue($picker->getComments()->contains($winners->first())); + $this->assertTrue($picker->getComments()->contains($winners->last())); + }); + } +}