[BSS-14] New Client Mechanism: Solution A vs Solution B #7
Closed
shahmal1yev
started this conversation in
Ideas
Replies: 3 comments
-
Solution CCode Example<?php
namespace Atproto;
use Atproto\Contracts\HTTP\RequestContract;
use Exception;
class Client
{
protected array $path = [];
public function __call(string $name, array $arguments): Client
{
$this->path[] = $name;
return $this;
}
protected function refresh(): void
{
$this->path = [];
}
/**
* @throws Exception
*/
public function build(): RequestContract
{
$namespace = $this->namespace();
if (! class_exists($namespace)) {
throw new Exception("$namespace class does not exist.");
}
return new $namespace;
}
protected function namespace(): string
{
$prefix = 'Atproto\\API\\';
$namespace = "$prefix" . implode('\\', array_map(
'ucfirst',
$this->path
));
$this->refresh();
return $namespace;
}
} Unit Tests<?php
namespace Tests\Unit\Atproto;
use Atproto\API\App\Bsky\Actor\GetProfile;
use Atproto\API\Com\Atrproto\Repo\CreateRecord;
use Atproto\Client;
use Atproto\Contracts\HTTP\RequestContract;
use Exception;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
class ClientTest extends TestCase
{
protected Client $client;
protected function setUp(): void
{
parent::setUp();
$this->client = new Client();
}
public function testClientIsInstanceOfClient(): void
{
$this->assertInstanceOf(Client::class, $this->client);
}
public function testCallReturnsSameInterface(): void
{
$this->assertInstanceOf(
Client::class,
$this->client
->app()
->bsky()
->actor()
);
}
public function testCallSavesPathToProperty(): void
{
$path = [
'app',
'bsky',
'actor',
];
foreach($path as $piece) {
$this->client->$piece();
}
$expected = $path;
$actual = $this->pathValue();
$this->assertEquals($expected, $actual);
}
/**
* @param array $pieces
* @return RequestContract
* @throws Exception
*/
public function instanceOfRequestContract(array $pieces): \Atproto\Contracts\HTTP\RequestContract
{
foreach($pieces as $piece) {
$this->client->$piece();
}
return $this->client->build();
}
/**
* @throws Exception
*/
public function testBuildReturnsCorrectInstanceOfRequestContract(): void
{
$pieces = ['app', 'bsky', 'actor', 'getProfile'];
$actual = $this->instanceOfRequestContract($pieces);
$this->assertInstanceOf(GetProfile::class, $actual);
}
public function testBuildThrowsExceptionWhenClassDoesNotExist(): void
{
$pieces = [
'invalid',
'request',
'class',
'path'
];
$namespace = "Atproto\\API\\" . implode("\\", array_map('ucfirst', $pieces));
$this->expectException(Exception::class);
$this->expectExceptionMessage("$namespace class does not exist.");
$this->instanceOfRequestContract($pieces);
}
/**
* @throws Exception
*/
public function testBuildRefreshesPathPropertyWhenRequestBuilt(): void
{
$getProfilePieces = ['app', 'bsky', 'actor', 'getProfile'];
$createRecordPieces = ['com', 'atrproto', 'repo', 'createRecord'];
$getProfile = $this->instanceOfRequestContract($getProfilePieces);
$createRecord = $this->instanceOfRequestContract($createRecordPieces);
$requests = [
GetProfile::class => $getProfile,
CreateRecord::class => $createRecord,
];
foreach($requests as $expected => $actual) {
$this->assertInstanceOf(RequestContract::class, $actual);
$this->assertInstanceOf($expected, $actual);
}
$actual = $this->pathValue();
$this->assertEmpty($actual);
}
protected function pathValue(): array
{
$reflection = new ReflectionClass($this->client);
$property = $reflection->getProperty('path');
$property->setAccessible(true);
return $property->getValue($this->client);
}
} |
Beta Was this translation helpful? Give feedback.
0 replies
-
public function build(array $arguments = []): RequestContract
{
$namespace = $this->namespace();
if (! class_exists($namespace)) {
throw new Exception("$namespace class does not exist.");
}
return new $namespace(...$arguments);
} |
Beta Was this translation helpful? Give feedback.
0 replies
-
Development started in #10 🐘 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
In this discussion, I will present two different solutions for the client mechanism. Each solution has its own advantages, requirements, and potential disadvantages. I look forward to your comments and feedback.
Solution A: Dynamic Finder and Class Loading
Requirements:
Description:
In this solution,
Finder
is used to dynamically locate classes in the file system, and they are automatically loaded based on the namespace structure. Paths are determined based on folder structure, and class names are resolved dynamically. When any method is called, the corresponding class is found, and necessary operations are performed.Advantages:
Disadvantages:
Code Example:
Solution B: Composer Autoload and Request Handler
Requirements:
Description:
In this solution, instead of dynamic file search, Composer's PSR-4 autoloading mechanism is used to find classes. Classes are automatically loaded, and requests are routed using a
RequestHandler
structure. Route definitions can be moved to a configuration file, and class dependencies are managed automatically with a Dependency Injection Container.Advantages:
Disadvantages:
Code Example:
Comparison Table:
Conclusion:
I look forward to discussing which solution might be more suitable for the project and hearing your suggestions for further improving both approaches!
Beta Was this translation helpful? Give feedback.
All reactions