Skip to content

Commit

Permalink
porting AnnotationBasedAutowiring for php-di v7
Browse files Browse the repository at this point in the history
  • Loading branch information
partikus committed Jan 10, 2024
1 parent 3174774 commit 40b4b87
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 49 deletions.
6 changes: 2 additions & 4 deletions src/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ class ContainerBuilder

private bool $useAutowiring = true;

private int $annotationsFlags = 0;

private bool $ignorePhpDocErrors = false;
private int $attributesFlags = 0;

private bool $useAttributes = false;

Expand Down Expand Up @@ -225,7 +223,7 @@ public function useAttributes(bool $bool, int $flags = 0) : self
$this->ensureNotLocked();

$this->useAttributes = $bool;
$this->annotationsFlags = $flags;
$this->attributesFlags = $flags;

return $this;
}
Expand Down
19 changes: 7 additions & 12 deletions src/Definition/AutowireDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,21 @@
*/
class AutowireDefinition extends ObjectDefinition
{
/**
* @var bool|null
*/
protected $useAnnotations;
protected ?bool $useAttributes;

/**
* Enable/disable reading annotations for this definition, regardless of a container configuration.
* @param bool $flag
* Enable/disable reading attributes for this definition, regardless of a container configuration.
*/
public function useAnnotations(bool $flag = true)
public function useAttributes(bool $flag = true) : void
{
$this->useAnnotations = $flag;
$this->useAttributes = $flag;
}

/**
* Returns boolean if the useAnnotation flag was explicitly set, otherwise null.
* @return bool|null
* Returns boolean if the useAttributes flag was explicitly set, otherwise null.
*/
public function isUsingAnnotations()
public function isUsingAttributes() : ?bool
{
return $this->useAnnotations;
return $this->useAttributes;
}
}
17 changes: 8 additions & 9 deletions src/Definition/Helper/AutowireDefinitionHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace DI\Definition\Helper;

use DI\Definition\AutowireDefinition;
use DI\Definition\Definition;
use DI\Definition\ObjectDefinition;

/**
* Helps defining how to create an instance of a class using autowiring.
Expand All @@ -16,7 +16,7 @@ class AutowireDefinitionHelper extends CreateDefinitionHelper
{
public const DEFINITION_CLASS = AutowireDefinition::class;

protected $useAnnotations;
protected ?bool $useAttributes = true;

/**
* Defines a value for a specific argument of the constructor.
Expand Down Expand Up @@ -74,27 +74,26 @@ public function methodParameter(string $method, string|int $parameter, mixed $va
}

/**
* Define if entry should use annotation reader for reading dependencies.
* Define if entry should use attributes reader for reading dependencies.
* This is turned off by default if autowire() helper is used, and turned on if entry is not defined explicitly in the di config.
* @param bool $useAnnotations
* @return $this
*/
public function useAnnotations(bool $useAnnotations = true)
public function useAttributes(bool $useAttributes = true) : self
{
$this->useAnnotations = $useAnnotations;
$this->useAttributes = $useAttributes;

return $this;
}

/**
* @return AutowireDefinition
*/
public function getDefinition(string $entryName) : Definition
public function getDefinition(string $entryName) : ObjectDefinition
{
/** @var AutowireDefinition $definition */
$definition = parent::getDefinition($entryName);
if ($this->useAnnotations !== null) {
$definition->useAnnotations($this->useAnnotations);
if ($this->useAttributes !== null) {
$definition->useAttributes($this->useAttributes);
}

return $definition;
Expand Down
48 changes: 24 additions & 24 deletions src/Definition/Source/AttributeBasedAutowiring.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ class AttributeBasedAutowiring implements DefinitionSource, Autowiring
{
// Annotations configuration flags:
// enable on implicit definitions
const IMPLICIT = 1;
public const IMPLICIT = 1;
// enable on all autowire definitions (which are written in DI config) by default
const EXPLICIT = 2;
public const EXPLICIT = 2;
// read @Injectable annotations for classes
const INJECTABLE = 4;
public const INJECTABLE = 4;
// read @Inject annotations for properties
const PROPERTIES = 8;
public const PROPERTIES = 8;
// read @Inject annotations for methods' parameters
const METHODS = 16;
public const METHODS = 16;
// all options enabled
const ALL = 31;
public const ALL = 31;

public function __construct(private int $flags = 0)
{
Expand All @@ -57,17 +57,17 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob
}

$definition = $definition ?: new ObjectDefinition($name);
$useAnnotations = $definition instanceof AutowireDefinition
? ($definition->isUsingAnnotations() ?? ($this->flags & self::EXPLICIT))
: ($this->flags & self::IMPLICIT);
$useAttributes = $definition instanceof AutowireDefinition
? ($definition->isUsingAttributes() ?? (bool) ($this->flags & self::EXPLICIT))
: (bool) ($this->flags & self::IMPLICIT);

$class = null;
if ($useAnnotations && $this->flags >= self::INJECTABLE) {
if ($useAttributes && $this->flags >= self::INJECTABLE) {
$class = new ReflectionClass($className);

$this->readInjectableAttribute($class, $definition);
$this->readInjectableAttribute($class, $definition);
if ($this->flags & self::INJECTABLE) {
$this->readInjectableAnnotation($class, $definition);
$this->readInjectableAttribute($class, $definition);
}

// Browse the class properties looking for annotated properties
Expand All @@ -83,8 +83,8 @@ public function autowire(string $name, ObjectDefinition $definition = null) : Ob

// constructor parameters should always be read, even if annotations are disabled (completely or i.a. for methods)
// so that it behaves at least as ReflectionBasedAutowiring
if (!$useAnnotations || !($this->flags & self::METHODS)) {
$class = $class ?? new ReflectionClass($className);
if (!$useAttributes || !($this->flags & self::METHODS)) {
$class ??= new ReflectionClass($className);
$this->readConstructor($class, $definition);
}

Expand All @@ -109,7 +109,7 @@ public function getDefinitions() : array
}

/**
* Browse the class properties looking for annotated properties.
* Browse the class properties looking for properties with attributes.
*/
private function readProperties(ReflectionClass $class, ObjectDefinition $definition) : void
{
Expand Down Expand Up @@ -182,7 +182,7 @@ private function readProperty(ReflectionProperty $property, ObjectDefinition $de
}

/**
* Browse the object's methods looking for annotated methods.
* Browse the object's methods looking for methods with attributes.
*/
private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) : void
{
Expand Down Expand Up @@ -214,17 +214,17 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection
if ($attribute) {
/** @var Inject $inject */
$inject = $attribute->newInstance();
$annotationParameters = $inject->getParameters();
$attributeParameters = $inject->getParameters();
} elseif ($method->isConstructor()) {
// #[Inject] on constructor is implicit, we continue
$annotationParameters = [];
$attributeParameters = [];
} else {
return null;
}

$parameters = [];
foreach ($method->getParameters() as $index => $parameter) {
$entryName = $this->getMethodParameter($index, $parameter, $annotationParameters);
$entryName = $this->getMethodParameter($index, $parameter, $attributeParameters);

if ($entryName !== null) {
$parameters[$index] = new Reference($entryName);
Expand All @@ -241,7 +241,7 @@ private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection
/**
* @return string|null Entry name or null if not found.
*/
private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters) : ?string
private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $attributeParameters) : ?string
{
// Let's check if this parameter has an #[Inject] attribute
$attribute = $parameter->getAttributes(Inject::class)[0] ?? null;
Expand All @@ -253,11 +253,11 @@ private function getMethodParameter(int $parameterIndex, ReflectionParameter $pa
}

// #[Inject] has definition for this parameter (by index, or by name)
if (isset($annotationParameters[$parameterIndex])) {
return $annotationParameters[$parameterIndex];
if (isset($attributeParameters[$parameterIndex])) {
return $attributeParameters[$parameterIndex];
}
if (isset($annotationParameters[$parameter->getName()])) {
return $annotationParameters[$parameter->getName()];
if (isset($attributeParameters[$parameter->getName()])) {
return $attributeParameters[$parameter->getName()];
}

// Skip optional parameters if not explicitly defined
Expand Down

0 comments on commit 40b4b87

Please sign in to comment.