Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
43 changes: 43 additions & 0 deletions src/AttributeResolver/Enum/DeclaringClassType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);

/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 6.0.0
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\AttributeResolver\Enum;

/**
* Enum representing the declaring class kind for an attribute target.
*/
enum DeclaringClassType: string
{
/**
* Declaring type is a class.
*/
case CLASS_TYPE = 'class';
Comment thread
josbeir marked this conversation as resolved.
Outdated

/**
* Declaring type is an interface.
*/
case INTERFACE = 'interface';

/**
* Declaring type is a trait.
*/
case TRAIT = 'trait';

/**
* Declaring type is an enum.
*/
case ENUM = 'enum';
}
38 changes: 38 additions & 0 deletions src/AttributeResolver/Enum/MethodVisibility.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);

/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 6.0.0
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\AttributeResolver\Enum;

/**
* Enum representing method visibility levels.
*/
enum MethodVisibility: string
{
/**
* Public visibility.
*/
case PUBLIC = 'public';

/**
* Protected visibility.
*/
case PROTECTED = 'protected';

/**
* Private visibility.
*/
case PRIVATE = 'private';
}
113 changes: 109 additions & 4 deletions src/AttributeResolver/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
namespace Cake\AttributeResolver;

use Cake\AttributeResolver\Enum\AttributeTargetType;
use Cake\AttributeResolver\Enum\DeclaringClassType;
use Cake\AttributeResolver\Enum\MethodVisibility;
use Cake\AttributeResolver\ValueObject\AttributeInfo;
use Cake\AttributeResolver\ValueObject\AttributeTarget;
use Generator;
Expand Down Expand Up @@ -245,6 +247,8 @@ protected function parseClass(
): Generator {
$className = $reflection->getName();
$startLine = $reflection->getStartLine();
$isDeclaringClassAbstract = $reflection->isAbstract();
$declaringClassType = $this->getDeclaringClassType($reflection);

// Parse class-level attributes
yield from $this->parseAttributes(
Expand All @@ -253,33 +257,86 @@ protected function parseClass(
$filePath,
$startLine === false ? 0 : $startLine,
$fileTime,
new AttributeTarget(AttributeTargetType::CLASS_TYPE, $className),
new AttributeTarget(
AttributeTargetType::CLASS_TYPE,
$className,
null,
$isDeclaringClassAbstract,
$declaringClassType,
),
$pluginName,
);

// Parse method attributes
foreach ($reflection->getMethods() as $method) {
yield from $this->parseMethod($method, $filePath, $fileTime, $className, $pluginName);
yield from $this->parseMethod(
$method,
$filePath,
$fileTime,
$className,
$isDeclaringClassAbstract,
$declaringClassType,
$pluginName,
);
}

// Parse property attributes
foreach ($reflection->getProperties() as $property) {
yield from $this->parseProperty($property, $filePath, $fileTime, $className, $pluginName);
yield from $this->parseProperty(
$property,
$filePath,
$fileTime,
$className,
$isDeclaringClassAbstract,
$declaringClassType,
$pluginName,
);
}

// Parse constant attributes
foreach ($reflection->getReflectionConstants() as $constant) {
yield from $this->parseConstant($constant, $filePath, $fileTime, $className, $pluginName);
yield from $this->parseConstant(
$constant,
$filePath,
$fileTime,
$className,
$isDeclaringClassAbstract,
$declaringClassType,
$pluginName,
);
}
}

/**
* Detect declaring class kind from reflection.
*
* @param \ReflectionClass $reflection Class reflection
* @return \Cake\AttributeResolver\Enum\DeclaringClassType
*/
protected function getDeclaringClassType(ReflectionClass $reflection): DeclaringClassType
{
if ($reflection->isInterface()) {
return DeclaringClassType::INTERFACE;
}
if ($reflection->isTrait()) {
return DeclaringClassType::TRAIT;
}
if ($reflection->isEnum()) {
return DeclaringClassType::ENUM;
}

return DeclaringClassType::CLASS_TYPE;
}

/**
* Parse method attributes.
*
* @param \ReflectionMethod $method Method reflection
* @param string $filePath File path
* @param int $fileTime File modification time
* @param string $className Declaring class name
* @param bool $isDeclaringClassAbstract Whether the declaring class is abstract
* @param \Cake\AttributeResolver\Enum\DeclaringClassType $declaringClassType Declaring class kind
* @param string|null $pluginName Plugin name
* @return \Generator<\Cake\AttributeResolver\ValueObject\AttributeInfo>
*/
Expand All @@ -288,13 +345,19 @@ protected function parseMethod(
string $filePath,
int $fileTime,
string $className,
bool $isDeclaringClassAbstract,
DeclaringClassType $declaringClassType,
?string $pluginName,
): Generator {
$startLine = $method->getStartLine();
$methodVisibility = $this->getMethodVisibility($method);
$target = new AttributeTarget(
AttributeTargetType::METHOD,
$method->getName(),
$className,
$isDeclaringClassAbstract,
$declaringClassType,
$methodVisibility,
);

yield from $this->parseAttributes(
Expand All @@ -314,18 +377,41 @@ protected function parseMethod(
$fileTime,
$className,
$method->getName(),
$isDeclaringClassAbstract,
$declaringClassType,
$methodVisibility,
$pluginName,
);
}
}

/**
* Detect method visibility from reflection metadata.
*
* @param \ReflectionMethod $method Method reflection
* @return \Cake\AttributeResolver\Enum\MethodVisibility
*/
protected function getMethodVisibility(ReflectionMethod $method): MethodVisibility
{
if ($method->isPrivate()) {
return MethodVisibility::PRIVATE;
}
if ($method->isProtected()) {
return MethodVisibility::PROTECTED;
}

return MethodVisibility::PUBLIC;
}

/**
* Parse property attributes.
*
* @param \ReflectionProperty $property Property reflection
* @param string $filePath File path
* @param int $fileTime File modification time
* @param string $className Declaring class name
* @param bool $isDeclaringClassAbstract Whether the declaring class is abstract
* @param \Cake\AttributeResolver\Enum\DeclaringClassType $declaringClassType Declaring class kind
* @param string|null $pluginName Plugin name
* @return \Generator<\Cake\AttributeResolver\ValueObject\AttributeInfo>
*/
Expand All @@ -334,12 +420,16 @@ protected function parseProperty(
string $filePath,
int $fileTime,
string $className,
bool $isDeclaringClassAbstract,
DeclaringClassType $declaringClassType,
?string $pluginName,
): Generator {
$target = new AttributeTarget(
AttributeTargetType::PROPERTY,
$property->getName(),
$className,
$isDeclaringClassAbstract,
$declaringClassType,
);

yield from $this->parseAttributes(
Expand All @@ -361,6 +451,9 @@ protected function parseProperty(
* @param int $fileTime File modification time
* @param string $className Declaring class name
* @param string $methodName Method name
* @param bool $isDeclaringClassAbstract Whether the declaring class is abstract
* @param \Cake\AttributeResolver\Enum\DeclaringClassType $declaringClassType Declaring class kind
* @param \Cake\AttributeResolver\Enum\MethodVisibility $methodVisibility Method visibility
* @param string|null $pluginName Plugin name
* @return \Generator<\Cake\AttributeResolver\ValueObject\AttributeInfo>
*/
Expand All @@ -370,6 +463,9 @@ protected function parseParameter(
int $fileTime,
string $className,
string $methodName,
bool $isDeclaringClassAbstract,
DeclaringClassType $declaringClassType,
MethodVisibility $methodVisibility,
?string $pluginName,
): Generator {
$declaringFunction = $parameter->getDeclaringFunction();
Expand All @@ -379,6 +475,9 @@ protected function parseParameter(
AttributeTargetType::PARAMETER,
$parameter->getName(),
$className . '::' . $methodName,
$isDeclaringClassAbstract,
$declaringClassType,
$methodVisibility,
);

yield from $this->parseAttributes(
Expand All @@ -399,6 +498,8 @@ protected function parseParameter(
* @param string $filePath File path
* @param int $fileTime File modification time
* @param string $className Declaring class name
* @param bool $isDeclaringClassAbstract Whether the declaring class is abstract
* @param \Cake\AttributeResolver\Enum\DeclaringClassType $declaringClassType Declaring class kind
* @param string|null $pluginName Plugin name
* @return \Generator<\Cake\AttributeResolver\ValueObject\AttributeInfo>
*/
Expand All @@ -407,12 +508,16 @@ protected function parseConstant(
string $filePath,
int $fileTime,
string $className,
bool $isDeclaringClassAbstract,
DeclaringClassType $declaringClassType,
?string $pluginName,
): Generator {
$target = new AttributeTarget(
AttributeTargetType::CONSTANT,
$constant->getName(),
$className,
$isDeclaringClassAbstract,
$declaringClassType,
);

yield from $this->parseAttributes(
Expand Down
Loading
Loading