Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F11724582
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Sep 18, 16:21 (12 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2991070
Default Alt Text
(7 KB)
Attached To
Mode
rKERUALD Keruald libraries development repository
Attached
Detach File
Event Timeline
Log In to Comment