Skip to content

Commit

Permalink
Add rector, raise PHP to ^8.0, minor refactoring (#41)
Browse files Browse the repository at this point in the history
Co-authored-by: Sergei Predvoditelev <sergei@predvoditelev.ru>
  • Loading branch information
xepozz and vjik committed Nov 1, 2022
1 parent 6b8c8b2 commit f21846c
Show file tree
Hide file tree
Showing 37 changed files with 402 additions and 563 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Expand Up @@ -13,5 +13,9 @@ trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false

[*.php]
ij_php_space_before_short_closure_left_parenthesis = true
ij_php_space_after_type_cast = true

[*.yml]
indent_size = 2
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Expand Up @@ -28,4 +28,4 @@ jobs:
os: >-
['ubuntu-latest', 'windows-latest']
php: >-
['7.4', '8.0', '8.1']
['8.0', '8.1']
21 changes: 21 additions & 0 deletions .github/workflows/rector.yml
@@ -0,0 +1,21 @@
on:
pull_request:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'
- 'infection.json.dist'
- 'psalm.xml'

name: rector

jobs:
rector:
uses: yiisoft/actions/.github/workflows/rector.yml@master
with:
os: >-
['ubuntu-latest']
php: >-
['8.0']
2 changes: 1 addition & 1 deletion .github/workflows/static.yml
Expand Up @@ -28,4 +28,4 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['7.4', '8.0', '8.1']
['8.0', '8.1']
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -2,7 +2,8 @@

## 2.1.1 under development

- Enh #44: In methods of array definitions add autowiring and improve variadic arguments support (@vjik)
- Enh #44: In methods of array definitions add autowiring and improve variadic arguments support (@vjik)
- Enh #41: Raise minimum PHP version to 8.0 and refactor code (@xepozz, @vjik)

## 2.1.0 October 25, 2022

Expand Down
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -26,14 +26,14 @@ The following are provided:

## Requirements

- PHP 7.4 or higher.
- PHP 8.0 or higher.

## Installation

The package could be installed with composer:

```shell
composer require yiisoft/definitions --prefer-dist
composer require yiisoft/definitions
```

## General usage
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -26,11 +26,12 @@
}
],
"require": {
"php": "^7.4|^8.0",
"php": "^8.0",
"psr/container": "^1.0|^2.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"rector/rector": "^0.14.3",
"roave/infection-static-analysis-plugin": "^1.18",
"spatie/phpunit-watcher": "^1.23",
"vimeo/psalm": "^4.22",
Expand Down
1 change: 0 additions & 1 deletion phpunit.xml.dist
Expand Up @@ -18,7 +18,6 @@
<testsuites>
<testsuite name="Yii Definitions tests">
<directory>./tests/Unit</directory>
<directory phpVersion="8" phpVersionOperator=">=">./tests/Php8</directory>
<directory phpVersion="8.1" phpVersionOperator=">=">./tests/Php8_1</directory>
</testsuite>
</testsuites>
Expand Down
22 changes: 22 additions & 0 deletions rector.php
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/src',
__DIR__ . '/tests',
]);

// register a single rule
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);

// define sets of rules
$rectorConfig->sets([
LevelSetList::UP_TO_PHP_80,
]);
};
22 changes: 6 additions & 16 deletions src/ArrayDefinition.php
Expand Up @@ -33,29 +33,19 @@ final class ArrayDefinition implements DefinitionInterface
public const TYPE_METHOD = 'method';

/**
* @psalm-var class-string
* Container used to resolve references.
*/
private string $class;
private array $constructorArguments;
/**
* Container used to resolve references.
*/
private ?ContainerInterface $referenceContainer = null;

/**
* @psalm-var array<string, MethodOrPropertyItem>
*/
private array $methodsAndProperties;

/**
* @psalm-param class-string $class
* @psalm-param array<string, MethodOrPropertyItem> $methodsAndProperties
*/
private function __construct(string $class, array $constructorArguments, array $methodsAndProperties)
{
$this->class = $class;
$this->constructorArguments = $constructorArguments;
$this->methodsAndProperties = $methodsAndProperties;
private function __construct(
private string $class,
private array $constructorArguments,
private array $methodsAndProperties
) {
}

/**
Expand Down
10 changes: 4 additions & 6 deletions src/CallableDefinition.php
Expand Up @@ -36,18 +36,18 @@ final class CallableDefinition implements DefinitionInterface
*
* @psalm-param callable|array{0:class-string,1:string} $callable
*/
public function __construct($callable)
public function __construct(array|callable $callable)
{
$this->callable = $callable;
}

public function resolve(ContainerInterface $container)
public function resolve(ContainerInterface $container): mixed
{
try {
$reflection = new ReflectionFunction(
$this->prepareClosure($this->callable, $container)
);
} catch (ReflectionException $e) {
} catch (ReflectionException) {
throw new NotInstantiableException(
'Can not instantiate callable definition. Got ' . var_export($this->callable, true)
);
Expand All @@ -60,11 +60,9 @@ public function resolve(ContainerInterface $container)
}

/**
* @param array|callable $callable
*
* @psalm-param callable|array{0:class-string,1:string} $callable
*/
private function prepareClosure($callable, ContainerInterface $container): Closure
private function prepareClosure(array|callable $callable, ContainerInterface $container): Closure
{
if (is_array($callable) && !is_object($callable[0])) {
$reflection = new ReflectionMethod($callable[0], $callable[1]);
Expand Down
11 changes: 4 additions & 7 deletions src/Contract/DefinitionInterface.php
Expand Up @@ -19,14 +19,11 @@ interface DefinitionInterface
* Resolve this definition.
*
* @throws InvalidConfigException If an object of incorrect type was created.
* @throws CircularReferenceException If there is a circular reference detected
* when resolving the definition.
* @throws NotFoundExceptionInterface If container does not know how to resolve
* the definition.
* @throws CircularReferenceException If there is a circular reference detected when resolving the definition.
* @throws NotFoundExceptionInterface If container does not know how to resolve the definition.
* @throws NotInstantiableException If an object can not be instantiated.
*
* @return mixed|null Ready to use object or null if definition can
* not be resolved and is marked as optional.
* @return mixed|null Ready to use object or null if definition can not be resolved and is marked as optional.
*/
public function resolve(ContainerInterface $container);
public function resolve(ContainerInterface $container): mixed;
}
6 changes: 3 additions & 3 deletions src/Contract/ReferenceInterface.php
Expand Up @@ -7,8 +7,8 @@
use Yiisoft\Definitions\Exception\InvalidConfigException;

/**
* Reference points to another named definition. Usually it is another service in the container
* or another object definition in the factory.
* Reference points to another named definition. Usually it is another service in the container or another object
* definition in the factory.
*/
interface ReferenceInterface extends DefinitionInterface
{
Expand All @@ -19,5 +19,5 @@ interface ReferenceInterface extends DefinitionInterface
*
* @throws InvalidConfigException When definition configuration is not valid.
*/
public static function to($id): self;
public static function to(mixed $id): self;
}
70 changes: 36 additions & 34 deletions src/DefinitionStorage.php
Expand Up @@ -17,20 +17,18 @@
*/
final class DefinitionStorage
{
private array $definitions;
private array $buildStack = [];
/** @psalm-suppress PropertyNotSetInConstructor */

private ?ContainerInterface $delegateContainer = null;
private bool $useStrictMode;

/**
* @param array $definitions Definitions to store.
* @param bool $useStrictMode If every dependency should be defined explicitly including classes.
*/
public function __construct(array $definitions = [], bool $useStrictMode = false)
{
$this->definitions = $definitions;
$this->useStrictMode = $useStrictMode;
public function __construct(
private array $definitions = [],
private bool $useStrictMode = false
) {
}

/**
Expand Down Expand Up @@ -70,7 +68,7 @@ public function getBuildStack(): array
*
* @return mixed|object Definition with a given ID.
*/
public function get(string $id)
public function get(string $id): mixed
{
if (!$this->has($id)) {
throw new RuntimeException("Service $id doesn't exist in DefinitionStorage.");
Expand All @@ -82,13 +80,16 @@ public function get(string $id)
* Set a definition.
*
* @param string $id ID to set definition for.
* @param mixed|object $definition Definition to set.
* @param mixed $definition Definition to set.
*/
public function set(string $id, $definition): void
public function set(string $id, mixed $definition): void
{
$this->definitions[$id] = $definition;
}

/**
* @throws CircularReferenceException
*/
private function isResolvable(string $id, array $building): bool
{
if (isset($this->definitions[$id])) {
Expand All @@ -110,7 +111,7 @@ private function isResolvable(string $id, array $building): bool

try {
$dependencies = DefinitionExtractor::fromClassName($id);
} catch (Throwable $e) {
} catch (Throwable) {
$this->buildStack += $building + [$id => 1];
return false;
}
Expand All @@ -132,29 +133,28 @@ private function isResolvable(string $id, array $building): bool
break;
}

/**
* @var ReflectionNamedType|ReflectionUnionType|null $type
* @psalm-suppress RedundantConditionGivenDocblockType
* @psalm-suppress UndefinedClass
*/
if ($type === null || (!$type instanceof ReflectionUnionType && $type->isBuiltin())) {
if (
($type instanceof ReflectionNamedType && $type->isBuiltin())
|| (!$type instanceof ReflectionNamedType && !$type instanceof ReflectionUnionType)
) {
$isResolvable = false;
break;
}

// PHP 8 union type is used as type hint
/** @psalm-suppress UndefinedClass, TypeDoesNotContainType */
/** @var ReflectionNamedType|ReflectionUnionType $type */

// Union type is used as type hint
if ($type instanceof ReflectionUnionType) {
$isUnionTypeResolvable = false;
$unionTypes = [];
/**
* @psalm-suppress UnnecessaryVarAnnotation Annotation below is needed in PHP 7.4
*
* @var ReflectionNamedType $unionType
*/
foreach ($type->getTypes() as $unionType) {
if (!$unionType->isBuiltin()) {
$typeName = $unionType->getName();
/**
* @psalm-suppress TypeDoesNotContainType
*
* @link https://github.com/vimeo/psalm/issues/6756
*/
if ($typeName === 'self') {
continue;
}
Expand All @@ -166,7 +166,6 @@ private function isResolvable(string $id, array $building): bool
}
}


if (!$isUnionTypeResolvable) {
foreach ($unionTypes as $typeName) {
if ($this->delegateContainer !== null && $this->delegateContainer->has($typeName)) {
Expand All @@ -183,25 +182,28 @@ private function isResolvable(string $id, array $building): bool
continue;
}

/** @var ReflectionNamedType|null $type */
// Our parameter has a class type hint
if ($type !== null && !$type->isBuiltin()) {
if (!$type->isBuiltin()) {
$typeName = $type->getName();
/**
* @psalm-suppress TypeDoesNotContainType
*
* @link https://github.com/vimeo/psalm/issues/6756
*/
if ($typeName === 'self') {
throw new CircularReferenceException(sprintf(
'Circular reference to "%s" detected while building: %s.',
$id,
implode(', ', array_keys($building))
));
throw new CircularReferenceException(
sprintf(
'Circular reference to "%s" detected while building: %s.',
$id,
implode(', ', array_keys($building))
)
);
}

/** @psalm-suppress RedundantPropertyInitializationCheck */
if (!$this->isResolvable($typeName, $building) && ($this->delegateContainer === null || !$this->delegateContainer->has($typeName))) {
if (
!$this->isResolvable($typeName, $building)
&& ($this->delegateContainer === null || !$this->delegateContainer->has($typeName))
) {
$isResolvable = false;
break;
}
Expand Down

0 comments on commit f21846c

Please sign in to comment.