Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed "type mismatch" errors #77

Merged
merged 4 commits into from
May 11, 2024
Merged
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
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"name": "okapi/aop",
"description": "PHP AOP is a PHP library that provides a powerful Aspect Oriented Programming (AOP) implementation for PHP.",
"version": "1.2.10",
"type": "library",
"homepage": "https://github.com/okapi-web/php-aop",
"license": "MIT",
Expand Down
6 changes: 0 additions & 6 deletions src/AopKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Okapi\Aop\Core\Container\{AspectManager, TransformerManager};
use Okapi\Aop\Core\Options;
use Okapi\Aop\Core\Processor\AspectProcessor;
use Okapi\Aop\Core\Transformer\NetteReflectionWithBetterReflection;
use Okapi\CodeTransformer\CodeTransformerKernel;
use Okapi\CodeTransformer\Core\AutoloadInterceptor\ClassLoader as CodeTransformerClassLoader;
use Okapi\CodeTransformer\Core\Cache\CachePaths as CodeTransformerCachePaths;
Expand Down Expand Up @@ -110,11 +109,6 @@ protected static function registerDependencyInjection(): void
*/
protected function preInit(): void
{
// Add internal transformers
$this->transformerManager->addTransformers([
NetteReflectionWithBetterReflection::class,
]);

// Add the aspects
$this->aspectManager->addAspects($this->aspects);

Expand Down
2 changes: 1 addition & 1 deletion src/Attributes/After.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* This attribute is used to mark a method as an after advice.
*/
#[Attribute(Attribute::TARGET_METHOD)]
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class After extends MethodAdvice
{
}
2 changes: 1 addition & 1 deletion src/Attributes/Around.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* This attribute is used to mark a method as an around advice.
*/
#[Attribute(Attribute::TARGET_METHOD)]
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Around extends MethodAdvice
{
}
2 changes: 1 addition & 1 deletion src/Attributes/Before.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* This attribute is used to mark a method as a before advice.
*/
#[Attribute(Attribute::TARGET_METHOD)]
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Before extends MethodAdvice
{
}
48 changes: 0 additions & 48 deletions src/Core/.phpstorm.meta.php

This file was deleted.

54 changes: 0 additions & 54 deletions src/Core/Transform/ProxiedClassModifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,17 +203,6 @@ private function changeVisibility(): void
private function replaceSelfType(): void
{
$this->nodeCallbacks[] = function (Node $node) {
// Replace parameter object types with the proxied class name
if ($node instanceof Node\Parameter
&& $node->typeDeclarationList instanceof Node\DelimitedList\QualifiedNameList
) {
foreach ($node->typeDeclarationList->children as $type) {
if ($type instanceof Node\QualifiedName) {
$this->replaceParameterSelfType($type);
}
}
}

// Replace return object types with the proxied class name
if ($node instanceof Node\MethodDeclaration
&& $node->returnTypeList instanceof Node\DelimitedList\QualifiedNameList
Expand All @@ -234,49 +223,6 @@ private function replaceSelfType(): void
};
}

/**
* Replace the parameter self type with the proxied class name.
*
* @param Node\QualifiedName $qualifiedName
*
* @return void
*
* @noinspection PhpDocMissingThrowsInspection
*/
private function replaceParameterSelfType(
Node\QualifiedName $qualifiedName,
): void {
$typeText = $qualifiedName->getText();

// Self
if ($typeText === 'self') {
$this->edit(
$qualifiedName,
$this->proxiedClassName,
);

return;
}

// Other classes that have a proxy
/** @noinspection PhpUnhandledExceptionInspection */
$fullClassName = '\\' . $qualifiedName->getResolvedName()
->getFullyQualifiedNameText();
$proxyClassName = $fullClassName
. $this->cachePaths::PROXIED_SUFFIX;

// Autoload the class with class_exists,
// so we can check if the proxy exists
if (class_exists($fullClassName)
&& class_exists($proxyClassName)
) {
$this->edit(
$qualifiedName,
$proxyClassName,
);
}
}

/**
* Replace the return self type with the proxied class name.
*
Expand Down
98 changes: 22 additions & 76 deletions src/Core/Transform/WovenClassBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\Factory;
use Nette\PhpGenerator\Method;
use Nette\PhpGenerator\Parameter;
use Nette\PhpGenerator\PhpNamespace;
use Nette\PhpGenerator\PromotedParameter;
use Nette\PhpGenerator\Property;
use Nette\Utils\Type;
use Okapi\Aop\Core\Cache\CachePaths;
use Okapi\Aop\Core\Container\AdviceContainer;
use Okapi\Aop\Core\Container\AdviceType\MethodAdviceContainer;
use Okapi\Aop\Core\JoinPoint\JoinPoint;
use Okapi\Aop\Core\JoinPoint\JoinPointInjector;
use Okapi\CodeTransformer\Core\DI;
use Okapi\CodeTransformer\Transformer\Code;
use Roave\BetterReflection\Reflection\Adapter\ReflectionMethod;
use Roave\BetterReflection\Reflection\ReflectionMethod as BetterReflectionMethod;

/**
Expand Down Expand Up @@ -206,24 +206,31 @@ private function buildMethods(): array
* @param BetterReflectionMethod $refMethod
*
* @return Method
*
* @noinspection PhpDocMissingThrowsInspection
*/
private function buildMethod(BetterReflectionMethod $refMethod): Method
{
$method = (new Factory)->fromMethodReflection($refMethod);
/** @noinspection PhpUnhandledExceptionInspection */
$method = (new Factory)->fromMethodReflection(
new ReflectionMethod($refMethod),
);

$methodName = $refMethod->getName();

// Replace parameter and return types with the proxied class
$declaringClass = $refMethod->getDeclaringClass();
$fullClassName = '\\' . $declaringClass->getNamespaceName()
. '\\' . $declaringClass->getShortName();
$proxiedClassName = $fullClassName . $this->cachePaths::PROXIED_SUFFIX;
foreach ($method->getParameters() as $parameter) {
$this->replaceParameterType($parameter, $proxiedClassName);
}
if ($method->getReturnType() === 'self') {
$method->setReturnType(
$proxiedClassName,
);
// ReadOnly Hack: https://github.com/nette/php-generator/issues/158
foreach ($refMethod->getParameters() as $refParameter) {
if ($refParameter->isPromoted()
&& ($declaringClass = $refParameter->getDeclaringClass())
&& ($refParameterName = $refParameter->getName())
&& $declaringClass->hasProperty($refParameterName)
&& ($property = $declaringClass->getProperty($refParameterName))
&& $property->isReadOnly()
) {
/** @var PromotedParameter $parameter */
$parameter = $method->getParameter($refParameterName);
$parameter->setReadOnly();
}
}

// Add "return" if the method has a return type
Expand Down Expand Up @@ -260,67 +267,6 @@ private function buildMethod(BetterReflectionMethod $refMethod): Method
return $method;
}

/**
* Replace the parameter type with the proxied class.
*
* @param Parameter|Type $parameterOrType
* @param string $proxiedClassName
*
* @return void
*/
private function replaceParameterType(
Parameter|Type $parameterOrType,
string $proxiedClassName
): void {
$objectType = $parameterOrType instanceof Parameter
? $parameterOrType->getType(true)
: $parameterOrType;
if (!$objectType) {
return;
}

$typeString = $this->getTypeString($objectType, $proxiedClassName);
$parameterOrType->setType($typeString);
}

/**
* Get the parameter array as a string.
*
* @param Type $type
* @param string $proxiedClassName
*
* @return string
*/
private function getTypeString(Type $type, string $proxiedClassName): string
{
// If the type is a union or intersection, we need to replace each type
if ($type->isUnion() || $type->isIntersection()) {
$typeNames = array_map(function ($type) use ($proxiedClassName) {
return $this->getTypeString($type, $proxiedClassName);
}, $type->getTypes());
$glue = $type->isUnion() ? '|' : '&';
return implode($glue, $typeNames);
} elseif ($type->getSingleName() === 'self') {
// If the type is "self", we need to replace it with the proxied
// class
return $proxiedClassName;
} elseif ($type->isClass()) {
// If the type is a class, we need to check if the class
// is a proxy
$typeFullClassName = '\\' . $type->getSingleName();
$typeProxiedClassName =
$typeFullClassName . $this->cachePaths::PROXIED_SUFFIX;

if (class_exists($typeFullClassName)
&& class_exists($typeProxiedClassName)
) {
return $typeProxiedClassName;
}
}

return $type->getSingleName();
}

/**
* Create an associative array with the parameter name as key and the
* parameter as value.
Expand Down
Loading