Page MenuHomeDevCentral

No OneTemporary

diff --git a/omnitools/src/Reflection/CodeClass.php b/omnitools/src/Reflection/CodeClass.php
index 1a7d9d0..d827e76 100644
--- a/omnitools/src/Reflection/CodeClass.php
+++ b/omnitools/src/Reflection/CodeClass.php
@@ -1,107 +1,111 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Reflection;
use Keruald\OmniTools\Collections\Vector;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
class CodeClass {
///
/// CodeClass constructor
///
public function __construct (
private readonly string $className,
) {
}
+ public static function from (object $object) : self {
+ return new self($object::class);
+ }
+
///
/// Class name helper methods
///
public function getClassName () : string {
return $this->className;
}
/**
* @throws ReflectionException
*/
public function getShortClassName () : string {
$class = new ReflectionClass($this->className);
return $class->getShortName();
}
///
/// Represented class constructor helper methods
///
/**
* @throws ReflectionException
* @throws InvalidArgumentException
*/
public function getConstructor () : ReflectionMethod {
$class = new ReflectionClass($this->className);
$constructor = $class->getConstructor();
return match ($constructor) {
null => throw new InvalidArgumentException(
"This class doesn't have a constructor."
),
default => $constructor,
};
}
/**
* @throws ReflectionException
*/
public function getConstructorArgumentsTypes () : Vector {
$class = new ReflectionClass($this->className);
$constructor = $class->getConstructor();
if ($constructor === null) {
return new Vector;
}
return CodeMethod::fromReflectionMethod($constructor)
->getArgumentsType();
}
/**
*
* This method can be used for dependency injection to build a class,
* like a controller in a MVC model, from a services' container.
*
* Each argument of the constructor is substituted by an item from
* $services. To match properly services and constructor arguments,
* each arguments need to have a type, and those types should properly
* exist in $services, without duplicate.
*
* @param iterable $services a collection with keys as type names and values
* @return object A new instance of the reflected class
* @throws ReflectionException
*/
public function newInstanceFromServices (iterable $services) : object {
$args = $this->getConstructorArgumentsTypes()
->map(function (string $type) use ($services) : mixed {
foreach ($services as $value) {
if (CodeVariable::from($value)->hasType($type)) {
return $value;
}
}
throw new InvalidArgumentException("No instance of type $type can be found.");
});
$class = new ReflectionClass($this->className);
return $class->newInstance(...$args);
}
}
diff --git a/omnitools/tests/Reflection/CodeClassTest.php b/omnitools/tests/Reflection/CodeClassTest.php
index 60d56b2..00fb36d 100644
--- a/omnitools/tests/Reflection/CodeClassTest.php
+++ b/omnitools/tests/Reflection/CodeClassTest.php
@@ -1,121 +1,129 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Tests\Reflection;
use Keruald\OmniTools\Collections\ArrayUtilities;
use Keruald\OmniTools\Collections\HashMap;
use Keruald\OmniTools\Collections\Vector;
use Keruald\OmniTools\DateTime\DateStamp;
use Keruald\OmniTools\HTTP\Requests\Request;
use Keruald\OmniTools\Network\IPv4Range;
use Keruald\OmniTools\Reflection\CodeClass;
use PHPUnit\Framework\TestCase;
use InvalidArgumentException;
class CodeClassTest extends TestCase {
private CodeClass $class;
protected function setUp () : void {
$this->class = new CodeClass(AcmeApplication::class);
}
+ public function testFrom () {
+ $date = new DateStamp(2010, 11, 25);
+ $class = CodeClass::from($date);
+
+ $this->assertInstanceOf(CodeClass::class, $class);
+ $this->assertEquals(DateStamp::class, $class->getClassName());
+ }
+
public function testGetClassName () {
$this->assertEquals(
AcmeApplication::class,
$this->class->getClassName(),
);
}
public function testGetShortClassName () {
$this->assertEquals(
"AcmeApplication",
$this->class->getShortClassName(),
);
}
public function testNewInstanceFromServices () {
$services = [
// Some objects (in different order than the constructor)
"request" => new Request(),
"date" => DateStamp::fromUnixTime(), // another name than in class
"session" => new HashMap(),
// Scalar values
"counter" => 666,
"isSecure" => false,
"temperature" => 26.6,
"inventory" => [],
// An object not needed by the controller
"ip_range" => IPv4Range::from("127.0.0.1/32"),
];
$app = $this->class->newInstanceFromServices($services);
$this->assertInstanceOf(AcmeApplication::class, $app);
$this->assertEquals($services["date"], $app->getDateStamp());
}
public function testNewInstanceFromServicesWithMissingService () {
$incompleteServices = [
"foo",
];
$this->expectException(InvalidArgumentException::class);
$this->class->newInstanceFromServices($incompleteServices);
}
public function testNewInstanceFromServicesWithoutConstructor () {
$services = [
"foo",
];
$class = new CodeClass(ArrayUtilities::class); // No constructor
$utilities = $class->newInstanceFromServices($services);
$this->assertInstanceOf(ArrayUtilities::class, $utilities);
}
public function testGetConstructorArgumentsTypes () {
$expected = Vector::from([
Request::class,
HashMap::class,
DateStamp::class,
"int",
"array",
"float",
"bool",
]);
$actual = $this->class->getConstructorArgumentsTypes();
$this->assertEquals($expected, $actual);
}
public function testGetConstructorArgumentsTypesWhenNotExisting () {
$class = new CodeClass(ArrayUtilities::class); // No constructor
$this->assertEquals(new Vector, $class->getConstructorArgumentsTypes());
}
public function testGetConstructor () {
$constructor = $this->class->getConstructor();
$this->assertEquals("__construct", $constructor->getName());
$this->assertEquals(
AcmeApplication::class,
$constructor->getDeclaringClass()->getName()
);
}
public function testGetConstructorWhenNotExisting () {
$this->expectException(InvalidArgumentException::class);
$class = new CodeClass(ArrayUtilities::class); // No constructor
$class->getConstructor();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Sep 18, 16:21 (2 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2991070
Default Alt Text
(7 KB)

Event Timeline