From 1b2da982301e7e6f6f2019c690db4fa2f338ab51 Mon Sep 17 00:00:00 2001 From: Chris Page Date: Tue, 12 Nov 2024 16:11:01 +0000 Subject: [PATCH] Added ability to define a description programmatically for each analytic item --- README.md | 12 +++++++ .../Laravel/Console/Commands/PanCommand.php | 2 +- .../DatabaseAnalyticsRepository.php | 19 ++++++++--- src/PanConfiguration.php | 33 ++++++++++++++++++- src/Presentors/AnalyticPresentor.php | 1 + src/ValueObjects/Analytic.php | 9 ++--- tests/Feature/Laravel/Http/EventsTest.php | 10 +++--- tests/Unit/Actions/CreateEventTest.php | 2 +- tests/Unit/PanConfigurationTest.php | 22 +++++++++++++ .../Unit/Presentors/AnalyticPresentorTest.php | 23 +++++++++++++ 10 files changed, 115 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 5b3a467..e74bcf4 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,18 @@ If you want to have unlimited analytics records, you may use the `Pan::unlimited PanConfiguration::unlimitedAnalytics(); ``` +## Provide a human description for your analytics + +If you want to add a human-readable description to your analytics, you may use the `PanConfiguration::analyticsDescriptions` method: + +```php +PanConfiguration::analyticDescriptions([ + 'button-cta' => 'Call to action button', +]); +``` + +These descriptions will be shown when you visualize your analytics via the `pan` Artisan command. + ## Configure the route prefix By default, Pan's route prefix is `/pan`, but you may change it by using the `PanConfiguration::routePrefix` method: diff --git a/src/Adapters/Laravel/Console/Commands/PanCommand.php b/src/Adapters/Laravel/Console/Commands/PanCommand.php index c6bfead..b7b931e 100644 --- a/src/Adapters/Laravel/Console/Commands/PanCommand.php +++ b/src/Adapters/Laravel/Console/Commands/PanCommand.php @@ -47,7 +47,7 @@ public function handle(AnalyticsRepository $analytics, AnalyticPresentor $presen } (new Table($this->output))->display( - ['', 'Name', 'Impressions', 'Hovers', 'Clicks'], + ['', 'Name', 'Description', 'Impressions', 'Hovers', 'Clicks'], array_map(fn (Analytic $analytic): array => array_values($presentor->present($analytic)), $analytics) ); } diff --git a/src/Adapters/Laravel/Repositories/DatabaseAnalyticsRepository.php b/src/Adapters/Laravel/Repositories/DatabaseAnalyticsRepository.php index 7e3d1da..4b0f1a3 100644 --- a/src/Adapters/Laravel/Repositories/DatabaseAnalyticsRepository.php +++ b/src/Adapters/Laravel/Repositories/DatabaseAnalyticsRepository.php @@ -15,12 +15,22 @@ */ final readonly class DatabaseAnalyticsRepository implements AnalyticsRepository { + /** + * @var array{ + * max_analytics: int, + * allowed_analytics: array, + * route_prefix: string, + * analytic_descriptions: array, + * } + */ + private array $config; + /** * Creates a new analytics repository instance. */ - public function __construct(private PanConfiguration $config) + public function __construct(PanConfiguration $config) { - // + $this->config = $config->toArray(); } /** @@ -36,7 +46,8 @@ public function all(): array name: $analytic->name, // @phpstan-ignore-line impressions: (int) $analytic->impressions, // @phpstan-ignore-line hovers: (int) $analytic->hovers, // @phpstan-ignore-line - clicks: (int) $analytic->clicks, // @phpstan-ignore-line + clicks: (int) $analytic->clicks, // @phpstan-ignore-line, + description: $this->config['analytic_descriptions'][$analytic->name] ?? null, // @phpstan-ignore-line ))->toArray(); return $all; @@ -50,7 +61,7 @@ public function increment(string $name, EventType $event): void [ 'allowed_analytics' => $allowedAnalytics, 'max_analytics' => $maxAnalytics, - ] = $this->config->toArray(); + ] = $this->config; if (count($allowedAnalytics) > 0 && ! in_array($name, $allowedAnalytics, true)) { return; diff --git a/src/PanConfiguration.php b/src/PanConfiguration.php index b70b4a1..9a2775d 100644 --- a/src/PanConfiguration.php +++ b/src/PanConfiguration.php @@ -15,11 +15,13 @@ final class PanConfiguration * Creates a new Pan configuration instance. * * @param array $allowedAnalytics + * @param array $analyticDescriptions */ private function __construct( private int $maxAnalytics = 50, private array $allowedAnalytics = [], private string $routePrefix = 'pan', + private array $analyticDescriptions = [], ) { // } @@ -66,6 +68,18 @@ public function setRoutePrefix(string $prefix): void $this->routePrefix = $prefix; } + /** + * Sets the analytic descriptions. + * + * @param array $descriptions + * + * @internal + */ + public function setAnalyticDescriptions(array $descriptions): void + { + $this->analyticDescriptions = $descriptions; + } + /** * Sets the maximum number of analytics to store. */ @@ -102,6 +116,16 @@ public static function routePrefix(string $prefix): void self::instance()->setRoutePrefix($prefix); } + /** + * Sets the analytics descriptions + * + * @param array $descriptions + */ + public static function analyticDescriptions(array $descriptions): void + { + self::instance()->setAnalyticDescriptions($descriptions); + } + /** * Resets the configuration to its default values. * @@ -112,12 +136,18 @@ public static function reset(): void self::maxAnalytics(50); self::allowedAnalytics([]); self::routePrefix('pan'); + self::analyticDescriptions([]); } /** * Converts the Pan configuration to an array. * - * @return array{max_analytics: int, allowed_analytics: array, route_prefix: string} + * @return array{ + * max_analytics: int, + * allowed_analytics: array, + * route_prefix: string, + * analytic_descriptions: array, + * } * * @internal */ @@ -127,6 +157,7 @@ public function toArray(): array 'max_analytics' => $this->maxAnalytics, 'allowed_analytics' => $this->allowedAnalytics, 'route_prefix' => $this->routePrefix, + 'analytic_descriptions' => $this->analyticDescriptions, ]; } } diff --git a/src/Presentors/AnalyticPresentor.php b/src/Presentors/AnalyticPresentor.php index 1f20889..83cef64 100644 --- a/src/Presentors/AnalyticPresentor.php +++ b/src/Presentors/AnalyticPresentor.php @@ -21,6 +21,7 @@ public function present(Analytic $analytic): array return [ 'id' => '#'.$analytic->id.'', 'name' => ''.$analytic->name.'', + 'description' => ''.($analytic->description ?? '-').'', 'impressions' => $this->toHumanReadableNumber($analytic->impressions), 'hovers' => $this->toHumanReadableNumber($analytic->hovers).' ('.$this->toHumanReadablePercentage($analytic->impressions, $analytic->hovers).')', 'clicks' => $this->toHumanReadableNumber($analytic->clicks).' ('.$this->toHumanReadablePercentage($analytic->impressions, $analytic->clicks).')', diff --git a/src/ValueObjects/Analytic.php b/src/ValueObjects/Analytic.php index 69fdcb9..0a3bdcf 100644 --- a/src/ValueObjects/Analytic.php +++ b/src/ValueObjects/Analytic.php @@ -9,17 +9,13 @@ */ final readonly class Analytic { - /** - * Returns all analytics. - * - * @return array - */ public function __construct( public int $id, public string $name, public int $impressions, public int $hovers, public int $clicks, + public ?string $description = null, ) { // } @@ -27,13 +23,14 @@ public function __construct( /** * Returns the analytic as an array. * - * @return array{id: int, name: string, impressions: int, hovers: int, clicks: int} + * @return array{id: int, name: string, description: string|null, impressions: int, hovers: int, clicks: int} */ public function toArray(): array { return [ 'id' => $this->id, 'name' => $this->name, + 'description' => $this->description, 'impressions' => $this->impressions, 'hovers' => $this->hovers, 'clicks' => $this->clicks, diff --git a/tests/Feature/Laravel/Http/EventsTest.php b/tests/Feature/Laravel/Http/EventsTest.php index 0408e80..2fbc0aa 100644 --- a/tests/Feature/Laravel/Http/EventsTest.php +++ b/tests/Feature/Laravel/Http/EventsTest.php @@ -18,7 +18,7 @@ $analytics = array_map(fn (Analytic $analytic): array => $analytic->toArray(), app(AnalyticsRepository::class)->all()); expect($analytics)->toBe([ - ['id' => 1, 'name' => 'help-modal', 'impressions' => 0, 'hovers' => 0, 'clicks' => 1], + ['id' => 1, 'name' => 'help-modal', 'description' => null, 'impressions' => 0, 'hovers' => 0, 'clicks' => 1], ]); }); @@ -35,7 +35,7 @@ $analytics = array_map(fn (Analytic $analytic): array => $analytic->toArray(), app(AnalyticsRepository::class)->all()); expect($analytics)->toBe([ - ['id' => 1, 'name' => 'help-modal', 'impressions' => 0, 'hovers' => 1, 'clicks' => 0], + ['id' => 1, 'name' => 'help-modal', 'description' => null, 'impressions' => 0, 'hovers' => 1, 'clicks' => 0], ]); }); @@ -52,7 +52,7 @@ $analytics = array_map(fn (Analytic $analytic): array => $analytic->toArray(), app(AnalyticsRepository::class)->all()); expect($analytics)->toBe([ - ['id' => 1, 'name' => 'help-modal', 'impressions' => 1, 'hovers' => 0, 'clicks' => 0], + ['id' => 1, 'name' => 'help-modal', 'description' => null, 'impressions' => 1, 'hovers' => 0, 'clicks' => 0], ]); }); @@ -75,7 +75,7 @@ $analytics = array_map(fn (Analytic $analytic): array => $analytic->toArray(), app(AnalyticsRepository::class)->all()); expect($analytics)->toBe([ - ['id' => 1, 'name' => 'help-modal', 'impressions' => 1, 'hovers' => 0, 'clicks' => 1], + ['id' => 1, 'name' => 'help-modal', 'description' => null, 'impressions' => 1, 'hovers' => 0, 'clicks' => 1], ]); }); @@ -135,7 +135,7 @@ $analytics = array_map(fn (Analytic $analytic): array => $analytic->toArray(), app(AnalyticsRepository::class)->all()); expect($analytics)->toBe([ - ['id' => 1, 'name' => 'help-modal', 'impressions' => 1, 'hovers' => 0, 'clicks' => 0], + ['id' => 1, 'name' => 'help-modal', 'description' => null, 'impressions' => 1, 'hovers' => 0, 'clicks' => 0], ]); })->after(function (): void { PanConfiguration::routePrefix('pan'); diff --git a/tests/Unit/Actions/CreateEventTest.php b/tests/Unit/Actions/CreateEventTest.php index f0aa086..5a13d17 100644 --- a/tests/Unit/Actions/CreateEventTest.php +++ b/tests/Unit/Actions/CreateEventTest.php @@ -15,6 +15,6 @@ $analytics = array_map(fn (Analytic $analytic): array => $analytic->toArray(), app(AnalyticsRepository::class)->all()); expect($analytics)->toBe([ - ['id' => 1, 'name' => 'help-modal', 'impressions' => 0, 'hovers' => 1, 'clicks' => 2], + ['id' => 1, 'name' => 'help-modal', 'description' => null, 'impressions' => 0, 'hovers' => 1, 'clicks' => 2], ]); }); diff --git a/tests/Unit/PanConfigurationTest.php b/tests/Unit/PanConfigurationTest.php index daf4bda..2dbda16 100644 --- a/tests/Unit/PanConfigurationTest.php +++ b/tests/Unit/PanConfigurationTest.php @@ -7,6 +7,7 @@ 'max_analytics' => 50, 'allowed_analytics' => [], 'route_prefix' => 'pan', + 'analytic_descriptions' => [], ]); }); @@ -17,6 +18,7 @@ 'max_analytics' => 100, 'allowed_analytics' => [], 'route_prefix' => 'pan', + 'analytic_descriptions' => [], ]); }); @@ -27,6 +29,7 @@ 'max_analytics' => PHP_INT_MAX, 'allowed_analytics' => [], 'route_prefix' => 'pan', + 'analytic_descriptions' => [], ]); }); @@ -37,6 +40,7 @@ 'max_analytics' => 50, 'allowed_analytics' => ['help-modal', 'contact-modal'], 'route_prefix' => 'pan', + 'analytic_descriptions' => [], ]); }); @@ -45,6 +49,7 @@ 'max_analytics' => 50, 'allowed_analytics' => [], 'route_prefix' => 'pan', + 'analytic_descriptions' => [], ]); }); @@ -55,18 +60,34 @@ 'max_analytics' => 50, 'allowed_analytics' => [], 'route_prefix' => 'new-pan', + 'analytic_descriptions' => [], + ]); +}); + +it('can set the event descriptions', function (): void { + PanConfiguration::analyticDescriptions([ + 'help-modal' => 'The Help Modal', + ]); + + expect(PanConfiguration::instance()->toArray())->toBe([ + 'max_analytics' => 50, + 'allowed_analytics' => [], + 'route_prefix' => 'pan', + 'analytic_descriptions' => ['help-modal' => 'The Help Modal'], ]); }); it('may reset the configuration to its default values', function (): void { PanConfiguration::maxAnalytics(99); PanConfiguration::allowedAnalytics(['help-modal', 'contact-modal']); + PanConfiguration::analyticDescriptions(['help-modal' => 'The help modal']); PanConfiguration::routePrefix('new-pan'); expect(PanConfiguration::instance()->toArray())->toBe([ 'max_analytics' => 99, 'allowed_analytics' => ['help-modal', 'contact-modal'], 'route_prefix' => 'new-pan', + 'analytic_descriptions' => ['help-modal' => 'The help modal'], ]); PanConfiguration::reset(); @@ -75,5 +96,6 @@ 'max_analytics' => 50, 'allowed_analytics' => [], 'route_prefix' => 'pan', + 'analytic_descriptions' => [], ]); }); diff --git a/tests/Unit/Presentors/AnalyticPresentorTest.php b/tests/Unit/Presentors/AnalyticPresentorTest.php index e735654..c12899c 100644 --- a/tests/Unit/Presentors/AnalyticPresentorTest.php +++ b/tests/Unit/Presentors/AnalyticPresentorTest.php @@ -13,6 +13,7 @@ expect($rows)->toBe([ 'id' => '#1', 'name' => 'help-modal', + 'description' => '-', 'impressions' => '1', 'hovers' => '1 (100.0%)', 'clicks' => '1 (100.0%)', @@ -29,6 +30,7 @@ expect($rows)->toBe([ 'id' => '#1', 'name' => 'help-modal', + 'description' => '-', 'impressions' => '0', 'hovers' => '1 (Infinity%)', 'clicks' => '1 (Infinity%)', @@ -45,6 +47,7 @@ expect($rows)->toBe([ 'id' => '#1', 'name' => 'help-modal', + 'description' => '-', 'impressions' => '1', 'hovers' => '0 (0.0%)', 'clicks' => '1 (100.0%)', @@ -61,6 +64,7 @@ expect($rows)->toBe([ 'id' => '#1', 'name' => 'help-modal', + 'description' => '-', 'impressions' => '1', 'hovers' => '1 (100.0%)', 'clicks' => '0 (0.0%)', @@ -77,6 +81,7 @@ expect($rows)->toBe([ 'id' => '#1', 'name' => 'help-modal', + 'description' => '-', 'impressions' => '1,000,000', 'hovers' => '1,000,000 (100.0%)', 'clicks' => '1,000,000 (100.0%)', @@ -93,8 +98,26 @@ expect($rows)->toBe([ 'id' => '#1', 'name' => 'help-modal', + 'description' => '-', 'impressions' => '0', 'hovers' => '1,000,000 (Infinity%)', 'clicks' => '1,000,000 (Infinity%)', ]); }); + +it('presents analytic with description', function (): void { + $analytic = new Analytic(1, 'help-modal', 1, 1, 1, 'The Help Modal'); + + $presentor = new AnalyticPresentor; + + $rows = array_map(fn ($value): string => strip_tags($value), $presentor->present($analytic)); + + expect($rows)->toBe([ + 'id' => '#1', + 'name' => 'help-modal', + 'description' => 'The Help Modal', + 'impressions' => '1', + 'hovers' => '1 (100.0%)', + 'clicks' => '1 (100.0%)', + ]); +});