Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/Adapters/Laravel/Console/Commands/PanCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final class PanCommand extends Command
*
* @var string
*/
protected $signature = 'pan {--filter= : Filter the analytics by name}';
protected $signature = 'pan {--filter= : Filter the analytics by name} {--tenant= : Show only analytics for specific tenant}';

/**
* The console command description.
Expand All @@ -40,6 +40,11 @@ public function handle(AnalyticsRepository $analytics, AnalyticPresentor $presen
$analytics = array_filter($analytics, fn (Analytic $analytic): bool => str_contains($analytic->name, $filter));
}

if (! empty($tenant = $this->option('tenant'))) {
$tenant = ctype_digit($tenant) ? (int) $tenant : $tenant;
$analytics = array_filter($analytics, fn (Analytic $analytic): bool => $analytic->tenant === $filter);
}

if ($analytics === []) {
$this->components->info('No analytics have been recorded yet. Get started collecting analytics by adding the [data-pan="my-button"] attribute to your HTML elements.');

Expand Down
40 changes: 31 additions & 9 deletions src/Adapters/Laravel/Repositories/DatabaseAnalyticsRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,18 @@ public function __construct(private PanConfiguration $config)
*/
public function all(): array
{
[
'tenant_field' => $tenantField,
] = $this->config->toArray();

/** @var array<int, Analytic> $all */
$all = DB::table('pan_analytics')->get()->map(fn (mixed $analytic): Analytic => new Analytic(
id: (int) $analytic->id, // @phpstan-ignore-line
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
id: (int) $analytic->id,
tenant: ($tenantField) ? $analytic->{$tenantField} : null,
name: $analytic->name,
impressions: (int) $analytic->impressions,
hovers: (int) $analytic->hovers,
clicks: (int) $analytic->clicks,
))->toArray();

return $all;
Expand All @@ -50,21 +55,38 @@ public function increment(string $name, EventType $event): void
[
'allowed_analytics' => $allowedAnalytics,
'max_analytics' => $maxAnalytics,
'tenant_field' => $tenantField,
'tenant_id' => $tenantId,
] = $this->config->toArray();

if (count($allowedAnalytics) > 0 && ! in_array($name, $allowedAnalytics, true)) {
return;
}

if (DB::table('pan_analytics')->where('name', $name)->count() === 0) {
if (DB::table('pan_analytics')->count() < $maxAnalytics) {
DB::table('pan_analytics')->insert(['name' => $name, $event->column() => 1]);
// Restrict query to tenant if tenant field and id are set
$baseQuery = DB::table('pan_analytics');

if ($tenantField !== null && $tenantId !== null) {
$baseQuery->where($tenantField, $tenantId);
}

$fieldQuery = clone $baseQuery;
$fieldQuery = $fieldQuery->where('name', $name);

if ($fieldQuery->count() === 0) {
if ($baseQuery->count() < $maxAnalytics) {
$baseQuery->insert(array_filter([
'name' => $name,
$event->column() => 1,
'tenant_field' => $tenantField,
'tenant_id' => $tenantId,
]));
}

return;
}

DB::table('pan_analytics')->where('name', $name)->increment($event->column());
$fieldQuery->increment($event->column());
}

/**
Expand Down
54 changes: 53 additions & 1 deletion src/PanConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ private function __construct(
private int $maxAnalytics = 50,
private array $allowedAnalytics = [],
private string $routePrefix = 'pan',
private ?string $tenantField = null,
private string|int|null $tenantId = null,
) {
//
}
Expand Down Expand Up @@ -66,6 +68,26 @@ public function setRoutePrefix(string $prefix): void
$this->routePrefix = $prefix;
}

/**
* Sets the tenant field to be used.
*
* @internal
*/
public function setTenantField(?string $field): void
{
$this->tenantField = $field;
}

/**
* Sets the tenant ID to be used.
*
* @internal
*/
public function setTenantId(string|int|null $id): void
{
$this->tenantId = $id;
}

/**
* Sets the maximum number of analytics to store.
*/
Expand Down Expand Up @@ -102,6 +124,26 @@ public static function routePrefix(string $prefix): void
self::instance()->setRoutePrefix($prefix);
}

/**
* Sets the tenant field to be used.
*
* @internal
*/
public static function tenantField(?string $field): void
{
self::instance()->setTenantField($field);
}

/**
* Sets the tenant ID to be used.
*
* @internal
*/
public static function tenantId(string|int|null $id): void
{
self::instance()->setTenantId($id);
}

/**
* Resets the configuration to its default values.
*
Expand All @@ -112,12 +154,20 @@ public static function reset(): void
self::maxAnalytics(50);
self::allowedAnalytics([]);
self::routePrefix('pan');
self::tenantField(null);
self::tenantId(null);
}

/**
* Converts the Pan configuration to an array.
*
* @return array{max_analytics: int, allowed_analytics: array<int, string>, route_prefix: string}
* @return array{
* max_analytics: int,
* allowed_analytics: array<int, string>,
* route_prefix: string,
* tenant_field: string|null,
* tenant_id: string|int|null,
* }
*
* @internal
*/
Expand All @@ -127,6 +177,8 @@ public function toArray(): array
'max_analytics' => $this->maxAnalytics,
'allowed_analytics' => $this->allowedAnalytics,
'route_prefix' => $this->routePrefix,
'tenant_field' => $this->tenantField,
'tenant_id' => $this->tenantId,
];
}
}
4 changes: 3 additions & 1 deletion src/ValueObjects/Analytic.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
public function __construct(
public int $id,
public string|int|null $tenant,
public string $name,
public int $impressions,
public int $hovers,
Expand All @@ -27,12 +28,13 @@ 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, tenant: string|int|null, name: string, impressions: int, hovers: int, clicks: int}
*/
public function toArray(): array
{
return [
'id' => $this->id,
'tenant' => $this->tenant,
'name' => $this->name,
'impressions' => $this->impressions,
'hovers' => $this->hovers,
Expand Down
10 changes: 10 additions & 0 deletions tests/Feature/Laravel/Console/PanTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Illuminate\Support\Facades\Artisan;
use Pan\Contracts\AnalyticsRepository;
use Pan\Enums\EventType;
use Pan\PanConfiguration;

it('displays analytics even if they are empty', function (): void {
$response = $this->artisan('pan');
Expand Down Expand Up @@ -48,3 +49,12 @@

expect($exitCode)->toBe(0);
});

it('displays tenant specific analytics', function (): void {
PanConfiguration::tenantField('team_id');
PanConfiguration::tenantId(1);

$exitCode = Artisan::call('pan --tenant=1');

expect($exitCode)->toBe(0);
});
10 changes: 5 additions & 5 deletions tests/Feature/Laravel/Http/EventsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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, 'tenant' => null, 'name' => 'help-modal', 'impressions' => 0, 'hovers' => 0, 'clicks' => 1],
]);
});

Expand All @@ -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, 'tenant' => null, 'name' => 'help-modal', 'impressions' => 0, 'hovers' => 1, 'clicks' => 0],
]);
});

Expand All @@ -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, 'tenant' => null, 'name' => 'help-modal', 'impressions' => 1, 'hovers' => 0, 'clicks' => 0],
]);
});

Expand All @@ -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, 'tenant' => null, 'name' => 'help-modal', 'impressions' => 1, 'hovers' => 0, 'clicks' => 1],
]);
});

Expand Down Expand Up @@ -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, 'tenant' => null, 'name' => 'help-modal', 'impressions' => 1, 'hovers' => 0, 'clicks' => 0],
]);
})->after(function (): void {
PanConfiguration::routePrefix('pan');
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Actions/CreateEventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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, 'tenant' => null, 'name' => 'help-modal', 'impressions' => 0, 'hovers' => 1, 'clicks' => 2],
]);
});
40 changes: 40 additions & 0 deletions tests/Unit/PanConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
'max_analytics' => 50,
'allowed_analytics' => [],
'route_prefix' => 'pan',
'tenant_field' => null,
'tenant_id' => null,
]);
});

Expand All @@ -17,6 +19,8 @@
'max_analytics' => 100,
'allowed_analytics' => [],
'route_prefix' => 'pan',
'tenant_field' => null,
'tenant_id' => null,
]);
});

Expand All @@ -27,6 +31,8 @@
'max_analytics' => PHP_INT_MAX,
'allowed_analytics' => [],
'route_prefix' => 'pan',
'tenant_field' => null,
'tenant_id' => null,
]);
});

Expand All @@ -37,6 +43,8 @@
'max_analytics' => 50,
'allowed_analytics' => ['help-modal', 'contact-modal'],
'route_prefix' => 'pan',
'tenant_field' => null,
'tenant_id' => null,
]);
});

Expand All @@ -45,6 +53,8 @@
'max_analytics' => 50,
'allowed_analytics' => [],
'route_prefix' => 'pan',
'tenant_field' => null,
'tenant_id' => null,
]);
});

Expand All @@ -55,6 +65,32 @@
'max_analytics' => 50,
'allowed_analytics' => [],
'route_prefix' => 'new-pan',
'tenant_field' => null,
'tenant_id' => null,
]);
});

it('can set the tenant field', function (): void {
PanConfiguration::tenantField('team_id');

expect(PanConfiguration::instance()->toArray())->toBe([
'max_analytics' => 50,
'allowed_analytics' => [],
'route_prefix' => 'pan',
'tenant_field' => 'team_id',
'tenant_id' => null,
]);
});

it('can set the tenant id', function (): void {
PanConfiguration::tenantId(1);

expect(PanConfiguration::instance()->toArray())->toBe([
'max_analytics' => 50,
'allowed_analytics' => [],
'route_prefix' => 'pan',
'tenant_field' => null,
'tenant_id' => 1,
]);
});

Expand All @@ -67,6 +103,8 @@
'max_analytics' => 99,
'allowed_analytics' => ['help-modal', 'contact-modal'],
'route_prefix' => 'new-pan',
'tenant_field' => null,
'tenant_id' => null,
]);

PanConfiguration::reset();
Expand All @@ -75,5 +113,7 @@
'max_analytics' => 50,
'allowed_analytics' => [],
'route_prefix' => 'pan',
'tenant_field' => null,
'tenant_id' => null,
]);
});
Loading