diff --git a/composer.json b/composer.json index 108de06..bdf7b19 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,8 @@ ], "require-dev": { "pestphp/pest": "1.22.2", - "worksome/coding-style": "2.3.2" + "worksome/coding-style": "2.3.2", + "mockery/mockery": "1.5.1" }, "require": { "php": "^8.2", diff --git a/config/cdn-headers.php b/config/cdn-headers.php new file mode 100644 index 0000000..d39d272 --- /dev/null +++ b/config/cdn-headers.php @@ -0,0 +1,10 @@ + env('CDN_HEADERS_PROVIDER', 'cloudflare'), + 'default-country' => env('CDN_COUNTRY_CODE', null), +]; diff --git a/src/CdnHeadersManager.php b/src/CdnHeadersManager.php index fd1bb98..b540f8f 100644 --- a/src/CdnHeadersManager.php +++ b/src/CdnHeadersManager.php @@ -3,27 +3,31 @@ namespace Worksome\CdnHeaders; use Illuminate\Support\Manager; -use JetBrains\PhpStorm\Pure; -use Worksome\CdnHeaders\CloudFlare\CloudFlareProvider; -use Worksome\CdnHeaders\Contracts\CdnHeadersProvider as CdnHeadersProviderContract; +use Worksome\CdnHeaders\Contracts\CdnHeadersProvider; +use Worksome\CdnHeaders\Providers\CloudFlare\CloudFlareProvider; +use Worksome\CdnHeaders\Providers\FakeProvider; class CdnHeadersManager extends Manager { - #[Pure] - public function createCloudFlareDriver(): CloudFlareProvider + public function createCloudFlareDriver(): CdnHeadersProvider { return new CloudFlareProvider( + $this->config->get('cdn-headers') ?? [], $this->container->get(ServerHeadersRepository::class) ); } - #[Pure] + public function createFakeDriver(): CdnHeadersProvider + { + return new FakeProvider($this->config->get('cdn-headers') ?? []); + } + public function getDefaultDriver(): string { - return 'cloudflare'; + return $this->config->get('cdn-headers.default-provider') ?? 'cloudflare'; } - public function provider(string $driver): CdnHeadersProviderContract + public function provider(string $driver): CdnHeadersProvider { return $this->driver($driver); } diff --git a/src/CdnHeadersServiceProvider.php b/src/CdnHeadersServiceProvider.php index 5cca855..ff9e168 100644 --- a/src/CdnHeadersServiceProvider.php +++ b/src/CdnHeadersServiceProvider.php @@ -5,13 +5,13 @@ use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider; -use Worksome\CdnHeaders\Contracts\CdnHeadersProvider as CdnHeadersProviderContract; +use Worksome\CdnHeaders\Contracts\CdnHeadersProvider; class CdnHeadersServiceProvider extends ServiceProvider implements DeferrableProvider { public function boot(): void { - $this->app->get(CdnHeadersProviderContract::class)->boot(); + $this->app->get(CdnHeadersProvider::class)->boot(); } public function register(): void @@ -22,13 +22,13 @@ public function register(): void ); $this->app->singleton( - CdnHeadersProviderContract::class, + CdnHeadersProvider::class, static fn(Container $app) => $app->get(CdnHeadersManager::class)->driver() ); } public function provides(): array { - return [CdnHeadersProviderContract::class, CdnHeadersManager::class]; + return [CdnHeadersProvider::class, CdnHeadersManager::class]; } } diff --git a/src/Contracts/CdnHeadersProvider.php b/src/Contracts/CdnHeadersProvider.php index 261b828..0629b74 100644 --- a/src/Contracts/CdnHeadersProvider.php +++ b/src/Contracts/CdnHeadersProvider.php @@ -10,7 +10,7 @@ interface CdnHeadersProvider * * @return non-empty-string|null */ - public function getCountryCode(): ?string; + public function getCountryCode(): string|null; public function hasCountryCode(): bool; @@ -19,9 +19,9 @@ public function hasCountryCode(): bool; * * @return non-empty-string|null */ - public function getConnectingIp(): ?string; + public function getConnectingIp(): string|null; - public function getTraceId(): ?string; + public function getTraceId(): string|null; /** * Anything required to be loaded in the boot diff --git a/src/CloudFlare/CloudFlareProvider.php b/src/Providers/CloudFlare/CloudFlareProvider.php similarity index 61% rename from src/CloudFlare/CloudFlareProvider.php rename to src/Providers/CloudFlare/CloudFlareProvider.php index 8d241b7..7bf47bb 100644 --- a/src/CloudFlare/CloudFlareProvider.php +++ b/src/Providers/CloudFlare/CloudFlareProvider.php @@ -1,6 +1,6 @@ serverHeaders->get('HTTP_CF_IPCOUNTRY'); + return $this->serverHeaders->get('HTTP_CF_IPCOUNTRY') ?? $this->config['default-country'] ?? null; } public function hasCountryCode(): bool @@ -22,17 +23,17 @@ public function hasCountryCode(): bool return (bool) $this->getCountryCode(); } - public function getConnectingIp(): ?string + public function getConnectingIp(): string|null { return $this->serverHeaders->get('HTTP_CF_CONNECTING_IP'); } /** - * https://support.cloudflare.com/hc/en-us/articles/203118044-What-is-the-CF-RAY-header-#h_f7a7396f-ec41-4c52-abf5-a110cadaca7c + * @link https://support.cloudflare.com/hc/en-us/articles/203118044-What-is-the-CF-RAY-header-#h_f7a7396f-ec41-4c52-abf5-a110cadaca7c * * @return non-empty-string|null */ - public function getTraceId(): ?string + public function getTraceId(): string|null { return $this->serverHeaders->get('HTTP_CF_RAY'); } diff --git a/src/Providers/FakeProvider.php b/src/Providers/FakeProvider.php new file mode 100644 index 0000000..419d9ae --- /dev/null +++ b/src/Providers/FakeProvider.php @@ -0,0 +1,36 @@ +config['default-country'] ?? null; + } + + public function hasCountryCode(): bool + { + return (bool) $this->getCountryCode(); + } + + public function getConnectingIp(): string|null + { + return null; + } + + public function getTraceId(): string|null + { + return null; + } + + public function boot(): void + { + } +} diff --git a/src/ServerHeadersRepository.php b/src/ServerHeadersRepository.php index 39cbbb0..c40f4a1 100644 --- a/src/ServerHeadersRepository.php +++ b/src/ServerHeadersRepository.php @@ -7,7 +7,7 @@ class ServerHeadersRepository /** * @return non-empty-string|null */ - public function get(string $key): ?string + public function get(string $key): string|null { if (isset($_SERVER[$key])) { return $_SERVER[$key]; diff --git a/tests/CdnHeadersManagerTest.php b/tests/CdnHeadersManagerTest.php new file mode 100644 index 0000000..a994e5b --- /dev/null +++ b/tests/CdnHeadersManagerTest.php @@ -0,0 +1,45 @@ +createMocks = function ($config) { + $this->mockContainer = Mockery::mock(Container::class); + $this->mockConfig = Mockery::mock(Repository::class); + $this->mockContainer->shouldReceive('make')->andReturn($this->mockConfig); + $this->mockContainer->shouldReceive('get')->andReturn(new ServerHeadersRepository()); + $this->mockConfig->shouldReceive('get') + ->with('cdn-headers.default-provider') + ->andReturn($config['default-provider']); + $this->mockConfig->shouldReceive('get') + ->with('cdn-headers') + ->andReturn($config); + }; +}); + +it('should return cloudflare as the default provider if no config param is present', function () { + $this->createMocks->__invoke([ + 'default-provider' => null, + ]); + $manager = new CdnHeadersManager($this->mockContainer); + expect($manager->getDefaultDriver())->toBe('cloudflare'); +}); + +it('should return fake as the provider if specified in config', function () { + $this->createMocks->__invoke([ + 'default-provider' => 'fake', + ]); + $manager = new CdnHeadersManager($this->mockContainer); + expect($manager->getDefaultDriver())->toBe('fake'); +}); + +it('should return cloudflare as the provider if specified in config', function () { + $this->createMocks->__invoke([ + 'default-provider' => 'cloudflare', + ]); + $manager = new CdnHeadersManager($this->mockContainer); + expect($manager->getDefaultDriver())->toBe('cloudflare'); +}); diff --git a/tests/CloudFlare/CloudFlareProviderTest.php b/tests/CloudFlare/CloudFlareProviderTest.php index 4531d26..eaf6b0e 100644 --- a/tests/CloudFlare/CloudFlareProviderTest.php +++ b/tests/CloudFlare/CloudFlareProviderTest.php @@ -1,21 +1,35 @@ $this->mock = Mockery::mock(ServerHeadersRepository::class)); +beforeEach(function () { + $this->country = 'GB'; + $this->mock = Mockery::mock(ServerHeadersRepository::class); + $this->config = [ + 'default-country' => $this->country, + ]; +}); -it('should get null as a default country code', function () { +it('should get null as a default country code if no config is present', function () { $this->mock->shouldReceive('get')->andReturn(null); - $provider = new CloudFlareProvider($this->mock); + $provider = new CloudFlareProvider([], $this->mock); expect($provider->getCountryCode())->toBe(null); expect($provider->hasCountryCode())->toBeFalse(); }); +it('should get config default country code if present', function () { + $this->mock->shouldReceive('get')->andReturn(null); + $provider = new CloudFlareProvider($this->config, $this->mock); + + expect($provider->getCountryCode())->toBe($this->country); + expect($provider->hasCountryCode())->toBeTrue(); +}); + it('should return a correct country code if server header present', function () { $this->mock->shouldReceive('get')->andReturn('US'); - $provider = new CloudFlareProvider($this->mock); + $provider = new CloudFlareProvider($this->config, $this->mock); expect($provider->getCountryCode())->toBe('US'); expect($provider->hasCountryCode())->toBeTrue(); @@ -23,24 +37,24 @@ it('should get null as a default connecting ip', function () { $this->mock->shouldReceive('get')->andReturn(null); - $provider = new CloudFlareProvider($this->mock); + $provider = new CloudFlareProvider($this->config, $this->mock); expect($provider->getConnectingIp())->toBe(null); }); it('should return an ip', function () { $this->mock->shouldReceive('get')->andReturn('127.0.0.1'); - $provider = new CloudFlareProvider($this->mock); + $provider = new CloudFlareProvider($this->config, $this->mock); expect($provider->getConnectingIp())->toBe('127.0.0.1'); }); it('should get null as a default ray', function () { $this->mock->shouldReceive('get')->andReturn(null); - $provider = new CloudFlareProvider($this->mock); + $provider = new CloudFlareProvider($this->config, $this->mock); expect($provider->getTraceId())->toBe(null); }); it('should return ray', function () { $this->mock->shouldReceive('get')->andReturn('CF12345679'); - $provider = new CloudFlareProvider($this->mock); + $provider = new CloudFlareProvider($this->config, $this->mock); expect($provider->getTraceId())->toBe('CF12345679'); }); diff --git a/tests/Faker/FakeProviderTest.php b/tests/Faker/FakeProviderTest.php new file mode 100644 index 0000000..f587e0f --- /dev/null +++ b/tests/Faker/FakeProviderTest.php @@ -0,0 +1,34 @@ +country = 'GB'; + $this->config = [ + 'default-country' => $this->country, + ]; +}); + +it('should get null as a default country code if no config is present', function () { + $provider = new FakeProvider([]); + + expect($provider->getCountryCode())->toBe(null); + expect($provider->hasCountryCode())->toBeFalse(); +}); + +it('should get config default country code if present', function () { + $provider = new FakeProvider($this->config); + + expect($provider->getCountryCode())->toBe($this->country); + expect($provider->hasCountryCode())->toBeTrue(); +}); + +it('should get null as a default connecting ip', function () { + $provider = new FakeProvider($this->config); + expect($provider->getConnectingIp())->toBe(null); +}); + +it('should get null as a default ray', function () { + $provider = new FakeProvider($this->config); + expect($provider->getTraceId())->toBe(null); +});