Skip to content

Commit

Permalink
Support docblock tags
Browse files Browse the repository at this point in the history
* Support DocBlock tags @Property, @property-read and @property-write.
* Use phpstan/phpdoc-parser package for DocBlock parsing.
* Add tests regarding DocBlock handling.
  • Loading branch information
marguskaidja authored Nov 4, 2022
1 parent 74ea42a commit 596b99c
Show file tree
Hide file tree
Showing 12 changed files with 521 additions and 271 deletions.
382 changes: 204 additions & 178 deletions README.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
],
"license": "MIT",
"require": {
"php": "^8.0"
"php": "^8.0",
"phpstan/phpdoc-parser": "^1.13"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
Expand Down
10 changes: 10 additions & 0 deletions src/Accessible.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
use margusk\Accessors\Exception\InvalidArgumentException;
use ReflectionException;

use function array_shift;
use function count;
use function current;
use function in_array;
use function is_array;
use function is_string;
use function strlen;
use function strtolower;
use function substr;

trait Accessible
{
/**
Expand Down
3 changes: 1 addition & 2 deletions src/Attr/ICase.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class ICase extends Attr
{
public function __construct()
{
/** @noinspection PhpRedundantOptionalArgumentInspection */
parent::__construct(true);
parent::__construct();
}
}
3 changes: 1 addition & 2 deletions src/Attr/Immutable.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class Immutable extends Attr
{
public function __construct()
{
/** @noinspection PhpRedundantOptionalArgumentInspection */
parent::__construct(true);
parent::__construct();
}
}
10 changes: 9 additions & 1 deletion src/Attr/Mutator.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
use Attribute;
use margusk\Accessors\Attr;

use function array_values;
use function count;
use function explode;
use function is_array;
use function is_string;
use function preg_match;
use function trim;

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS)]
class Mutator extends Attr
{
Expand Down Expand Up @@ -56,4 +64,4 @@ public function mutator(): string|array|null
{
return $this->mutator;
}
}
}
85 changes: 61 additions & 24 deletions src/Attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@
namespace margusk\Accessors;

use margusk\Accessors\Attr\{Delete, Get, ICase, Immutable, Mutator, Set};
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionProperty;

use function array_fill_keys;
use function array_key_exists;
use function strtolower;

class Attributes
{
/** @var class-string[] */
Expand All @@ -33,34 +38,12 @@ class Attributes
/** @var array<class-string, Attr|null> */
private array $attributes;

/**
* @param ReflectionClass<object>|ReflectionProperty|null $rfObject
*/
public function __construct(ReflectionClass|ReflectionProperty|null $rfObject)
public function __construct()
{
$this->attributes = array_fill_keys(self::AVAILABLE_ATTR_NAMES, null);

/* $rfObject can be null to allow "empty" Attributes to be generated */
if (null !== $rfObject) {
// Read attributes from reflection object
foreach (
$rfObject->getAttributes(
Attr::class,
ReflectionAttribute::IS_INSTANCEOF
) as $rfAttribute
) {
$n = $rfAttribute->getName();

if (true === array_key_exists($n, $this->attributes)) {
/** @var Attr $inst */
$inst = $rfAttribute->newInstance();
$this->attributes[$n] = $inst;
}
}
}
}

public function mergeToParent(Attributes $parent): static
public function mergeWithParent(Attributes $parent): static
{
$new = clone $this;

Expand All @@ -77,4 +60,58 @@ public function get(string $name): ?Attr
{
return $this->attributes[$name] ?? null;
}

/**
* @param ReflectionClass<object>|ReflectionProperty $rfObject
*
* @return self
*/
public static function fromReflection(ReflectionClass|ReflectionProperty $rfObject): self
{
$that = new self();

foreach (
$rfObject->getAttributes(
Attr::class,
ReflectionAttribute::IS_INSTANCEOF
) as $rfAttribute
) {
$n = $rfAttribute->getName();

if (true === array_key_exists($n, $that->attributes)) {
/** @var Attr $inst */
$inst = $rfAttribute->newInstance();
$that->attributes[$n] = $inst;
}
}

return $that;
}

public static function fromDocBlock(PhpDocTagNode $tagNode): ?self
{
/** @var array<class-string<Attr>> $found */
$found = match(strtolower($tagNode->name)) {
'@property' => [Get::class, Set::class],
'@property-read' => [Get::class],
'@property-write' => [Set::class],
default => []
};

if (0 === count($found)) {
return null;
}

$that = new self();

foreach ($found as $n) {
if (true === array_key_exists($n, $that->attributes)) {
/** @var Attr $inst */
$inst = new $n(true);
$that->attributes[$n] = $inst;
}
}

return $that;
}
}
Loading

0 comments on commit 596b99c

Please sign in to comment.