Skip to content

Commit

Permalink
AttributesPropertyLister now caches the results in memory.
Browse files Browse the repository at this point in the history
  • Loading branch information
priyadi committed Sep 27, 2023
1 parent cd55f25 commit 38e7c5e
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 0.1.3

* `AttributesPropertyLister` now caches the results in memory.

## 0.1.2

* FileType: Catch `MappingException` on `getDescription()`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,37 @@
/**
* Determines all the file association properties by looking at
* AsFileAssociation attributes.
*
* @todo: expensive
*/
class AttributesPropertyLister implements PropertyListerInterface
{
/**
* @var array<string,iterable<string>>
*/
private array $cache = [];

public function getFileProperties(object $object): iterable
{
foreach (self::getReflectionPropertiesWithAttribute($object, AsFileAssociation::class) as $reflectionProperty) {
yield $reflectionProperty->getName();
if (isset($this->cache[get_class($object)])) {
return $this->cache[get_class($object)];
}

$class = get_class($object);
$properties = [];

foreach (self::getReflectionPropertiesWithAttribute($class, AsFileAssociation::class) as $reflectionProperty) {
$properties[$reflectionProperty->getName()] = 1;
}

return $this->cache[$class] = array_keys($properties);
}

/**
* @param class-string $class
* @return iterable<\ReflectionProperty>
*/
private static function getReflectionProperties(object $object): iterable
private static function getReflectionProperties(string $class): iterable
{
$reflectionClass = (new \ReflectionClass(get_class($object)));
$reflectionClass = (new \ReflectionClass($class));
while ($reflectionClass instanceof \ReflectionClass) {
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
if ($reflectionProperty->isStatic()) {
Expand All @@ -51,14 +64,15 @@ private static function getReflectionProperties(object $object): iterable
}

/**
* @param class-string $class
* @param class-string $attribute
* @return iterable<\ReflectionProperty>
*/
private static function getReflectionPropertiesWithAttribute(
object $object,
string $class,
string $attribute
): iterable {
foreach (self::getReflectionProperties($object) as $reflectionProperty) {
foreach (self::getReflectionProperties($class) as $reflectionProperty) {
$attributes = $reflectionProperty
->getAttributes($attribute);

Expand Down
41 changes: 41 additions & 0 deletions tests/FileAssociation/PropertyListerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/file-src package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\File\Tests\FileAssociation;

use PHPUnit\Framework\TestCase;
use Rekalogika\File\Association\PropertyLister\AttributesPropertyLister;
use Rekalogika\File\Tests\Model\EntityWithAttribute;
use Rekalogika\File\Tests\Model\SubclassOfEntityWithAttribute;

class PropertyListerTest extends TestCase
{
public function testAttributePropertyLister(): void
{
$lister = new AttributesPropertyLister();

$entity = new EntityWithAttribute('id');
$properties = $lister->getFileProperties($entity);
$properties = $properties instanceof \Traversable
? \iterator_to_array($properties)
: $properties;
$this->assertSame(['file'], $properties);

$subclassedEntity = new SubclassOfEntityWithAttribute('id');
$properties = $lister->getFileProperties($subclassedEntity);
$properties = $properties instanceof \Traversable
? \iterator_to_array($properties)
: $properties;
$this->assertSame(['anotherFile', 'file'], $properties);
}
}
68 changes: 68 additions & 0 deletions tests/Model/EntityWithAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/file-src package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\File\Tests\Model;

use Rekalogika\Contracts\File\FileInterface;
use Rekalogika\File\Association\Attribute\AsFileAssociation;

class EntityWithAttribute
{
#[AsFileAssociation]
private ?FileInterface $file = null;

private ?FileInterface $nonAssociatedFile = null;

public function __construct(
private string $id
) {
}

public function getId(): string
{
return $this->id;
}

/**
* @phpstan-impure
*/
public function getFile(): ?FileInterface
{
return $this->file;
}

public function setFile(?FileInterface $file): self
{
$this->file = $file;

return $this;
}

/**
* Get the value of nonAssociatedFile
*/
public function getNonAssociatedFile(): ?FileInterface
{
return $this->nonAssociatedFile;
}

/**
* Set the value of nonAssociatedFile
*/
public function setNonAssociatedFile(?FileInterface $nonAssociatedFile): self
{
$this->nonAssociatedFile = $nonAssociatedFile;

return $this;
}
}
61 changes: 61 additions & 0 deletions tests/Model/SubclassOfEntityWithAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/file-src package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\File\Tests\Model;

use Rekalogika\Contracts\File\FileInterface;
use Rekalogika\File\Association\Attribute\AsFileAssociation;

class SubclassOfEntityWithAttribute extends EntityWithAttribute
{
#[AsFileAssociation]
private ?FileInterface $anotherFile = null;

private ?FileInterface $unmanagedFile = null;

/**
* Get the value of anotherFile
*/
public function getAnotherFile(): ?FileInterface
{
return $this->anotherFile;
}

/**
* Set the value of anotherFile
*/
public function setAnotherFile(?FileInterface $anotherFile): self
{
$this->anotherFile = $anotherFile;

return $this;
}

/**
* Get the value of unmanagedFile
*/
public function getUnmanagedFile(): ?FileInterface
{
return $this->unmanagedFile;
}

/**
* Set the value of unmanagedFile
*/
public function setUnmanagedFile(?FileInterface $unmanagedFile): self
{
$this->unmanagedFile = $unmanagedFile;

return $this;
}
}

0 comments on commit 38e7c5e

Please sign in to comment.