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
5 changes: 4 additions & 1 deletion system/Config/BaseConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class BaseConfig
* An optional array of classes that will act as Registrars
* for rapidly setting config class properties.
*
* @var array
* @var list<class-string|object>
*/
public static $registrars = [];

Expand Down Expand Up @@ -70,6 +70,9 @@ class BaseConfig
*/
protected static $moduleConfig;

/**
* @param array<string, mixed> $array
*/
public static function __set_state(array $array)
{
static::$override = false;
Expand Down
6 changes: 4 additions & 2 deletions system/Config/BaseService.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@
* @method static Security security(App $config = null, $getShared = true)
* @method static Session session(ConfigSession $config = null, $getShared = true)
* @method static SiteURIFactory siteurifactory(App $config = null, Superglobals $superglobals = null, $getShared = true)
* @method static Superglobals superglobals(array $server = null, array $get = null, bool $getShared = true)
* @method static Superglobals superglobals(array<string, mixed> $server = null, array<string, mixed> $get = null, bool $getShared = true)
* @method static Throttler throttler($getShared = true)
* @method static Timer timer($getShared = true)
* @method static Toolbar toolbar(ConfigToolbar $config = null, $getShared = true)
Expand Down Expand Up @@ -178,7 +178,7 @@ class BaseService
/**
* A cache of other service classes we've found.
*
* @var array
* @var array{}
*
* @deprecated 4.5.0 No longer used.
*/
Expand Down Expand Up @@ -317,6 +317,8 @@ public static function locator(bool $getShared = true)
* Provides the ability to perform case-insensitive calling of service
* names.
*
* @param array<array-key, mixed> $arguments
*
* @return object|null
*/
public static function __callStatic(string $name, array $arguments)
Expand Down
4 changes: 4 additions & 0 deletions system/Config/DotEnv.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public function load(): bool

/**
* Parse the .env file into an array of key => value
*
* @return array<string, string>|null
*/
public function parse(): ?array
{
Expand Down Expand Up @@ -119,6 +121,8 @@ protected function setVariable(string $name, string $value = '')
/**
* Parses for assignment, cleans the $name and $value, and ensures
* that nested variables are handled.
*
* @return array{string, string}
*/
public function normaliseVariable(string $name, string $value = ''): array
{
Expand Down
33 changes: 23 additions & 10 deletions system/Config/Factories.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* instantiation checks.
*
* @method static BaseConfig|null config(...$arguments)
* @method static Model|null models(string $alias, array $options = [], ?ConnectionInterface &$conn = null)
* @method static Model|null models(string $alias, array<string, bool|string|null> $options = [], ?ConnectionInterface &$conn = null)
* @see \CodeIgniter\Config\FactoriesTest
*/
final class Factories
Expand Down Expand Up @@ -127,6 +127,8 @@ public static function define(string $component, string $alias, string $classnam
* Loads instances based on the method component name. Either
* creates a new instance or returns an existing shared instance.
*
* @param array<array-key, mixed> $arguments
*
* @return object|null
*/
public static function __callStatic(string $component, array $arguments)
Expand All @@ -140,7 +142,7 @@ public static function __callStatic(string $component, array $arguments)
// Determine the component-specific options
$options = array_merge(self::getOptions($component), $options);

if (! $options['getShared']) {
if (! (bool) $options['getShared']) {
if (isset(self::$aliases[$options['component']][$alias])) {
$class = self::$aliases[$options['component']][$alias];

Expand Down Expand Up @@ -192,6 +194,9 @@ public static function get(string $component, string $alias): ?object
/**
* Gets the defined instance. If not exists, creates new one.
*
* @param array<string, bool|string|null> $options
* @param array<array-key, mixed> $arguments
*
* @return object|null
*/
private static function getDefinedInstance(array $options, string $alias, array $arguments)
Expand Down Expand Up @@ -230,6 +235,8 @@ private static function getDefinedInstance(array $options, string $alias, array

/**
* Creates the shared instance.
*
* @param array<array-key, mixed> $arguments
*/
private static function createInstance(string $component, string $class, array $arguments): void
{
Expand Down Expand Up @@ -264,8 +271,8 @@ private static function isConfig(string $component): bool
/**
* Finds a component class
*
* @param array $options The array of component-specific directives
* @param string $alias Class alias. See the $aliases property.
* @param array<string, bool|string|null> $options The array of component-specific directives
* @param string $alias Class alias. See the $aliases property.
*/
private static function locateClass(array $options, string $alias): ?string
{
Expand Down Expand Up @@ -341,8 +348,8 @@ private static function isNamespaced(string $alias): bool
/**
* Verifies that a class & config satisfy the "preferApp" option
*
* @param array $options The array of component-specific directives
* @param string $alias Class alias. See the $aliases property.
* @param array<string, bool|string|null> $options The array of component-specific directives
* @param string $alias Class alias. See the $aliases property.
*/
private static function verifyPreferApp(array $options, string $alias): bool
{
Expand All @@ -362,8 +369,8 @@ private static function verifyPreferApp(array $options, string $alias): bool
/**
* Verifies that a class & config satisfy the "instanceOf" option
*
* @param array $options The array of component-specific directives
* @param string $alias Class alias. See the $aliases property.
* @param array<string, bool|string|null> $options The array of component-specific directives
* @param string $alias Class alias. See the $aliases property.
*/
private static function verifyInstanceOf(array $options, string $alias): bool
{
Expand Down Expand Up @@ -408,8 +415,8 @@ public static function getOptions(string $component): array
/**
* Normalizes, stores, and returns the configuration for a specific component
*
* @param string $component Lowercase, plural component name
* @param array $values option values
* @param string $component Lowercase, plural component name
* @param array<string, bool|string|null> $values Option values
*
* @return array<string, bool|string|null> The result after applying defaults and normalization
*/
Expand Down Expand Up @@ -541,6 +548,12 @@ public static function getComponentInstances(string $component): array
/**
* Sets component data
*
* @param array{
* options: array<string, bool|string|null>,
* aliases: array<string, class-string>,
* instances: array<class-string, object>,
* } $data
*
* @internal For caching only
*/
public static function setComponentInstances(string $component, array $data): void
Expand Down
4 changes: 2 additions & 2 deletions system/Config/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Factory extends BaseConfig
* Supplies a default set of options to merge for
* all unspecified factory components.
*
* @var array
* @var array<string, bool|string|null>
*/
public static $default = [
'component' => null,
Expand All @@ -42,7 +42,7 @@ class Factory extends BaseConfig
* Specifies that Models should always favor child
* classes to allow easy extension of module Models.
*
* @var array
* @var array<string, bool|string|null>
*/
public $models = [
'preferApp' => true,
Expand Down
11 changes: 10 additions & 1 deletion system/Config/Services.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ public static function csp(?CSPConfig $config = null, bool $getShared = true)
* The CURL Request class acts as a simple HTTP client for interacting
* with other servers, typically through APIs.
*
* @param array<string, mixed> $options
*
* @return CURLRequest
*/
public static function curlrequest(array $options = [], ?ResponseInterface $response = null, ?App $config = null, bool $getShared = true)
Expand All @@ -220,7 +222,7 @@ public static function curlrequest(array $options = [], ?ResponseInterface $resp
/**
* The Email class allows you to send email via mail, sendmail, SMTP.
*
* @param array|EmailConfig|null $config
* @param array<string, mixed>|EmailConfig|null $config
*
* @return Email
*/
Expand Down Expand Up @@ -739,6 +741,13 @@ public static function siteurifactory(
/**
* Superglobals.
*
* @param array<string, mixed>|null $server
* @param array<string, mixed>|null $get
* @param array<string, mixed>|null $post
* @param array<string, mixed>|null $cookie
* @param array<string, mixed>|null $files
* @param array<string, mixed>|null $request
*
* @return Superglobals
*/
public static function superglobals(
Expand Down
3 changes: 3 additions & 0 deletions tests/system/Config/DotEnvTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ public function testLoadsVars(string $expected, string $varname): void
$this->assertSame($expected, getenv($varname));
}

/**
* @return iterable<array{string, string}>
*/
public static function provideLoadsVars(): iterable
{
yield from [
Expand Down
40 changes: 21 additions & 19 deletions tests/system/Config/FactoriesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ protected function setUp(): void
Factories::reset();
}

protected function getFactoriesStaticProperty(...$params): mixed
protected function getFactoriesStaticProperty(string ...$params): mixed
{
// First parameter is the actual property
$name = array_shift($params);
Expand Down Expand Up @@ -158,14 +158,14 @@ public function testGetsBasenameInvalid(): void

public function testCreatesByBasename(): void
{
$result = Factories::widgets('SomeWidget', ['getShared' => false]);
$result = Factories::widgets('SomeWidget', ['getShared' => false]); // @phpstan-ignore staticMethod.notFound

$this->assertInstanceOf(SomeWidget::class, $result);
}

public function testCreatesByClassname(): void
{
$result = Factories::widgets(SomeWidget::class, ['getShared' => false]);
$result = Factories::widgets(SomeWidget::class, ['getShared' => false]); // @phpstan-ignore staticMethod.notFound

$this->assertInstanceOf(SomeWidget::class, $result);
}
Expand All @@ -179,22 +179,22 @@ public function testCreatesByAbsoluteClassname(): void

public function testCreatesInvalid(): void
{
$result = Factories::widgets('gfnusvjai', ['getShared' => false]);
$result = Factories::widgets('gfnusvjai', ['getShared' => false]); // @phpstan-ignore staticMethod.notFound

$this->assertNull($result);
}

public function testIgnoresNonClass(): void
{
$result = Factories::widgets('NopeWidget', ['getShared' => false]);
$result = Factories::widgets('NopeWidget', ['getShared' => false]); // @phpstan-ignore staticMethod.notFound

$this->assertNull($result);
}

public function testReturnsSharedInstance(): void
{
$widget1 = Factories::widgets('SomeWidget');
$widget2 = Factories::widgets(SomeWidget::class);
$widget1 = Factories::widgets('SomeWidget'); // @phpstan-ignore staticMethod.notFound
$widget2 = Factories::widgets(SomeWidget::class); // @phpstan-ignore staticMethod.notFound

$this->assertSame($widget1, $widget2);
}
Expand All @@ -203,7 +203,7 @@ public function testInjection(): void
{
Factories::injectMock('widgets', 'Banana', new stdClass());

$result = Factories::widgets('Banana');
$result = Factories::widgets('Banana'); // @phpstan-ignore staticMethod.notFound

$this->assertInstanceOf('stdClass', $result);
}
Expand All @@ -212,7 +212,7 @@ public function testRespectsComponentAlias(): void
{
Factories::setOptions('tedwigs', ['component' => 'widgets']);

$result = Factories::tedwigs('SomeWidget');
$result = Factories::tedwigs('SomeWidget'); // @phpstan-ignore staticMethod.notFound
$this->assertInstanceOf(SomeWidget::class, $result);
}

Expand All @@ -228,26 +228,26 @@ public function testRespectsInstanceOf(): void
{
Factories::setOptions('widgets', ['instanceOf' => 'stdClass']);

$result = Factories::widgets('SomeWidget');
$result = Factories::widgets('SomeWidget'); // @phpstan-ignore staticMethod.notFound
$this->assertInstanceOf(SomeWidget::class, $result);

$result = Factories::widgets('OtherWidget');
$result = Factories::widgets('OtherWidget'); // @phpstan-ignore staticMethod.notFound
$this->assertNull($result);
}

public function testSharedRespectsInstanceOf(): void
{
Factories::injectMock('widgets', 'SomeWidget', new OtherWidget());

$result = Factories::widgets('SomeWidget', ['instanceOf' => 'stdClass']);
$result = Factories::widgets('SomeWidget', ['instanceOf' => 'stdClass']); // @phpstan-ignore staticMethod.notFound
$this->assertInstanceOf(SomeWidget::class, $result);
}

public function testPrioritizesParameterOptions(): void
{
Factories::setOptions('widgets', ['instanceOf' => 'stdClass']);

$result = Factories::widgets(OtherWidget::class, ['instanceOf' => null]);
$result = Factories::widgets(OtherWidget::class, ['instanceOf' => null]); // @phpstan-ignore staticMethod.notFound
$this->assertInstanceOf(OtherWidget::class, $result);
}

Expand All @@ -259,7 +259,7 @@ public function testFindsAppFirst(): void
class_alias(SomeWidget::class, $class);
}

$result = Factories::widgets('OtherWidget');
$result = Factories::widgets('OtherWidget'); // @phpstan-ignore staticMethod.notFound
$this->assertInstanceOf(SomeWidget::class, $result);
}

Expand All @@ -277,6 +277,7 @@ class TestRegistrar

$result = Factories::config('TestRegistrar');

// @phpstan-ignore argument.type (Config\TestRegistrar is created at runtime by this test)
$this->assertInstanceOf('Config\TestRegistrar', $result);

// Delete the config class in App
Expand Down Expand Up @@ -317,14 +318,14 @@ public function testPreferAppIsIgnored(): void
class_alias(SomeWidget::class, $class);
}

$result = Factories::widgets(OtherWidget::class);
$result = Factories::widgets(OtherWidget::class); // @phpstan-ignore staticMethod.notFound
$this->assertInstanceOf(OtherWidget::class, $result);
}

public function testCanLoadTwoCellsWithSameShortName(): void
{
$cell1 = Factories::cells('\\' . SampleClass::class);
$cell2 = Factories::cells('\\' . \Tests\Support\View\OtherCells\SampleClass::class);
$cell1 = Factories::cells('\\' . SampleClass::class); // @phpstan-ignore staticMethod.notFound
$cell2 = Factories::cells('\\' . \Tests\Support\View\OtherCells\SampleClass::class); // @phpstan-ignore staticMethod.notFound

$this->assertNotSame($cell1, $cell2);
}
Expand Down Expand Up @@ -369,6 +370,7 @@ public function testDefineSameAliasAndSameClassTwice(): void
UserModel::class,
);

// @phpstan-ignore codeigniter.modelArgumentType (aliased to Tests\Support\Models\UserModel above)
$model = model('CodeIgniter\Shield\Models\UserModel');

$this->assertInstanceOf(UserModel::class, $model);
Expand All @@ -382,7 +384,7 @@ public function testDefineNonExistentClass(): void
Factories::define(
'models',
'CodeIgniter\Shield\Models\UserModel',
'App\Models\UserModel',
'App\Models\UserModel', // @phpstan-ignore argument.type (deliberately does not exist)
);
}

Expand All @@ -398,7 +400,7 @@ public function testDefineAfterLoading(): void
Factories::define(
'models',
UserModel::class,
'App\Models\UserModel',
'App\Models\UserModel', // @phpstan-ignore argument.type (deliberately does not exist)
);
}

Expand Down
Loading
Loading