Skip to content

Commit

Permalink
feat(Config): Add ability to provider app service provider config
Browse files Browse the repository at this point in the history
- By using `HasConfig` interface on service provider you can merge own provider config and user defined config.
- Also name of the config is same as generated service file name.
- See ValidConfig and LoadProviderConfigTest
  • Loading branch information
pionl committed May 2, 2023
1 parent 449ba5c commit 1c5c1c7
Show file tree
Hide file tree
Showing 21 changed files with 334 additions and 33 deletions.
31 changes: 31 additions & 0 deletions src/Config/AbstractProviderConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace LaraStrict\Config;

use Illuminate\Config\Repository;
use LaraStrict\Providers\AbstractServiceProvider;
use LaraStrict\Providers\Actions\GetAppServiceProviderForClassAction;

abstract class AbstractProviderConfig extends AbstractConfig
{
public function __construct(
Repository $config,
private readonly GetAppServiceProviderForClassAction $getAppServiceProviderForClassAction
) {
parent::__construct($config);
}

/**
* @return class-string<AbstractServiceProvider>
*/
abstract protected function getServiceProvider(): string;

protected function getConfigFileName(): string
{
$appService = $this->getAppServiceProviderForClassAction->execute($this->getServiceProvider());

return $appService->serviceFileName;
}
}
2 changes: 1 addition & 1 deletion src/Config/Laravel/AppConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,6 @@ public function getEnvironment(): EnvironmentType|string

protected function getConfigFileName(): string
{
return self::ConfigName;
return 'app';
}
}
14 changes: 14 additions & 0 deletions src/Providers/AbstractBaseServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use LaraStrict\Contracts\RunAppServiceProviderPipesActionContract;
use LaraStrict\Providers\Actions\CreateAppServiceProviderAction;
use LaraStrict\Providers\Entities\AppServiceProviderEntity;
use LogicException;

abstract class AbstractBaseServiceProvider extends EventServiceProvider
{
Expand Down Expand Up @@ -60,6 +61,19 @@ public function laraLoadTranslationsFrom(string $path, string $namespace): void
$this->loadTranslationsFrom($path, $namespace);
}

public function laraLoadProviderConfigFrom(string $path, string $namespace): void
{
$serviceFileName = $namespace . '.php';
$configPath = $path . '/Config/' . $serviceFileName;
$realPath = realpath($configPath);

if ($realPath === false) {
throw new LogicException('Failed to load config at ' . $configPath);
}

$this->mergeConfigFrom($realPath, $namespace);
}

/**
* @return array<class-string<AppServiceProviderPipeContract>>
*/
Expand Down
3 changes: 2 additions & 1 deletion src/Providers/AbstractServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use LaraStrict\Providers\Pipes\BootProviderRoutesPipe;
use LaraStrict\Providers\Pipes\BootProviderViewComponents;
use LaraStrict\Providers\Pipes\BootViewComposersPipe;
use LaraStrict\Providers\Pipes\LoadProviderConfig;
use LaraStrict\Providers\Pipes\LoadProviderTranslations;
use LaraStrict\Providers\Pipes\LoadProviderViews;

Expand Down Expand Up @@ -48,7 +49,7 @@ public function boot(): void

protected function registerPipes(): array
{
return [LoadProviderViews::class, LoadProviderTranslations::class];
return [LoadProviderViews::class, LoadProviderTranslations::class, LoadProviderConfig::class];
}

protected function bootPipes(): array
Expand Down
49 changes: 49 additions & 0 deletions src/Providers/Actions/GetAppServiceProviderForClassAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace LaraStrict\Providers\Actions;

use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\ServiceProvider;
use LaraStrict\Cache\Contracts\CacheMeServiceContract;
use LaraStrict\Cache\Enums\CacheMeStrategy;
use LaraStrict\Providers\AbstractServiceProvider;
use LaraStrict\Providers\Entities\AppServiceProviderEntity;
use LogicException;

class GetAppServiceProviderForClassAction
{
public function __construct(
private readonly CacheMeServiceContract $cacheMeService,
) {
}

/**
* @param class-string<AbstractServiceProvider> $providerClass
*/
public function execute(string $providerClass): AppServiceProviderEntity
{
return $this->cacheMeService->get(
key: 'app-service-provider-' . $providerClass,
getValue: static function (Application $application) use ($providerClass) {
// TODO add ability to cache getProvider (laravel patch)
$serviceProvider = $application->getProvider($providerClass);
if ($serviceProvider instanceof ServiceProvider === false) {
throw new LogicException(sprintf('Provider for <%s> not loaded ', $providerClass));
}

if ($serviceProvider instanceof AbstractServiceProvider === false) {
throw new LogicException(sprintf(
'Provider <%s> must use <%s>',
$providerClass,
AbstractServiceProvider::class,
));
}

return $serviceProvider->getAppServiceProvider();
},
strategy: CacheMeStrategy::Memory
);
}
}
9 changes: 9 additions & 0 deletions src/Providers/Contracts/HasConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace LaraStrict\Providers\Contracts;

interface HasConfig
{
}
25 changes: 25 additions & 0 deletions src/Providers/Pipes/LoadProviderConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace LaraStrict\Providers\Pipes;

use Closure;
use LaraStrict\Contracts\AppServiceProviderPipeContract;
use LaraStrict\Providers\Contracts\HasConfig;
use LaraStrict\Providers\Entities\AppServiceProviderEntity;

class LoadProviderConfig implements AppServiceProviderPipeContract
{
public function handle(AppServiceProviderEntity $appServiceProvider, Closure $next): void
{
if ($appServiceProvider->serviceProvider instanceof HasConfig) {
$appServiceProvider->serviceProvider->laraLoadProviderConfigFrom(
path: $appServiceProvider->serviceRootDir,
namespace: $appServiceProvider->serviceFileName
);
}

$next($appServiceProvider);
}
}
4 changes: 2 additions & 2 deletions src/Providers/Pipes/LoadProviderTranslations.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ public function handle(AppServiceProviderEntity $appServiceProvider, Closure $ne
{
if ($appServiceProvider->serviceProvider instanceof HasTranslations) {
$appServiceProvider->serviceProvider->laraLoadTranslationsFrom(
$appServiceProvider->serviceRootDir . '/Translations',
$appServiceProvider->serviceName
path: $appServiceProvider->serviceRootDir . '/Translations',
namespace: $appServiceProvider->serviceName
);
}

Expand Down
32 changes: 8 additions & 24 deletions src/Translations/AbstractProviderTranslations.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,22 @@
namespace LaraStrict\Translations;

use Illuminate\Contracts\Translation\Translator;
use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider;
use LaraStrict\Providers\AbstractServiceProvider;
use LogicException;
use LaraStrict\Providers\Actions\GetAppServiceProviderForClassAction;

abstract class AbstractProviderTranslations extends AbstractTranslations
{
protected readonly string $providerKey;

public function __construct(Translator $translator, Application $application)
{
public function __construct(
Translator $translator,
GetAppServiceProviderForClassAction $getAppServiceProviderForClassAction
) {
parent::__construct($translator);

// TODO add ability to cache getProvider (laravel patch)
$providerClass = $this->getProviderClass();
$serviceProvider = $application->getProvider($providerClass);

if ($serviceProvider instanceof ServiceProvider === false) {
throw new LogicException(sprintf('Provider for translation <%s> not loaded ', $providerClass));
}

if ($serviceProvider instanceof AbstractServiceProvider === false) {
throw new LogicException(sprintf(
'Provider <%s> for translation must use <%s>',
$providerClass,
AbstractServiceProvider::class,
));
}

$this->providerKey = $serviceProvider
->getAppServiceProvider()
->serviceName;
$appService = $getAppServiceProviderForClassAction->execute($this->getProviderClass());

$this->providerKey = $appService->serviceName;
}

/**
Expand Down
34 changes: 34 additions & 0 deletions tests/Feature/Config/AbstractProviderConfigTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Config;

use Tests\LaraStrict\Feature\Config\NotUsingPipe\Config\NotUsingPipeConfig;
use Tests\LaraStrict\Feature\Config\NotUsingPipe\NotUsingPipeServiceProvider;
use Tests\LaraStrict\Feature\Config\Valid\Config\ValidConfig;
use Tests\LaraStrict\Feature\Config\Valid\ValidConfigServiceProvider;
use Tests\LaraStrict\Feature\TestCase;

class AbstractProviderConfigTest extends TestCase
{
public function testValid(): void
{
$this->app()
->register(provider: ValidConfigServiceProvider::class);
$config = $this->app()
->make(ValidConfig::class);

$this->assertEquals('value!', $config->getTest());
}

public function testNotUsingPipe(): void
{
$this->app()
->register(provider: NotUsingPipeServiceProvider::class);
$config = $this->app()
->make(NotUsingPipeConfig::class);

$this->assertEquals('missing file, this is a default', $config->getTest());
}
}
2 changes: 1 addition & 1 deletion tests/Feature/Config/Laravel/AppConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,6 @@ protected function setEnv(mixed $value): void

protected function getConfigName(): string
{
return AppConfig::ConfigName;
return 'app';
}
}
21 changes: 21 additions & 0 deletions tests/Feature/Config/NotUsingPipe/Config/NotUsingPipeConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Config\NotUsingPipe\Config;

use LaraStrict\Config\AbstractProviderConfig;
use Tests\LaraStrict\Feature\Config\NotUsingPipe\NotUsingPipeServiceProvider;

class NotUsingPipeConfig extends AbstractProviderConfig
{
public function getTest(): string
{
return $this->get(keyOrPath: ['test', 'sub-key'], default: 'missing file, this is a default');
}

protected function getServiceProvider(): string
{
return NotUsingPipeServiceProvider::class;
}
}
11 changes: 11 additions & 0 deletions tests/Feature/Config/NotUsingPipe/NotUsingPipeServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Config\NotUsingPipe;

use LaraStrict\Providers\AbstractServiceProvider;

class NotUsingPipeServiceProvider extends AbstractServiceProvider
{
}
23 changes: 23 additions & 0 deletions tests/Feature/Config/Valid/Config/ValidConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Config\Valid\Config;

use LaraStrict\Config\AbstractProviderConfig;
use Tests\LaraStrict\Feature\Config\Valid\ValidConfigServiceProvider;

class ValidConfig extends AbstractProviderConfig
{
final public const KeyTest = 'test';

public function getTest(): string
{
return $this->get(self::KeyTest);
}

protected function getServiceProvider(): string
{
return ValidConfigServiceProvider::class;
}
}
9 changes: 9 additions & 0 deletions tests/Feature/Config/Valid/Config/valid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

use Tests\LaraStrict\Feature\Config\Valid\Config\ValidConfig;

return [
ValidConfig::KeyTest => 'value!',
];
12 changes: 12 additions & 0 deletions tests/Feature/Config/Valid/ValidConfigServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Config\Valid;

use LaraStrict\Providers\AbstractServiceProvider;
use LaraStrict\Providers\Contracts\HasConfig;

class ValidConfigServiceProvider extends AbstractServiceProvider implements HasConfig
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Providers\Pipes\LoadProviderConfig\Invalid;

use Illuminate\Support\ServiceProvider;
use LaraStrict\Providers\Contracts\HasConfig;

class InvalidConfigServiceProvider extends ServiceProvider implements HasConfig
{
}
Loading

0 comments on commit 1c5c1c7

Please sign in to comment.