From 20fbf6facc037ead7af231ca6b217b29679ebf0c Mon Sep 17 00:00:00 2001 From: Frederik Schmitt Date: Sun, 17 Dec 2023 14:20:48 +0100 Subject: [PATCH] Allow adding custom resources Fixes #70 --- README.md | 45 ++++++++++++++++++++++++++++++++++++ examples/custom-resource.php | 43 ++++++++++++++++++++++++++++++++++ src/Keycloak.php | 12 ++++++++++ 3 files changed, 100 insertions(+) create mode 100644 examples/custom-resource.php diff --git a/README.md b/README.md index 9275f40..d74ba85 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,51 @@ Keycloak 23.0.0 is running on Linux/5.10.25-linuxkit (amd64) with OpenJDK 64-Bit More examples can be found in the [examples](examples) directory. +## Customization + +### Custom representations & resources + +You can register and use custom resources by providing your own representations and resources, e.g.: +```php +class MyCustomRepresentation extends \Fschmtt\Keycloak\Representation\Representation +{ + public function __construct( + protected ?string $id = null, + protected ?string $name = null, + ) { + } +} + +class MyCustomResource extends \Fschmtt\Keycloak\Resource\Resource +{ + public function myCustomEndpoint(): MyCustomRepresentation + { + return $this->queryExecutor->executeQuery( + new \Fschmtt\Keycloak\Http\Query( + '/my-custom-endpoint', + MyCustomRepresentation::class, + ) + ); + } +} +``` + +By extending the `Resource` class, you have access to both the `QueryExecutor` and `CommandExecutor`. +The `CommandExecutor` is designed to run state-changing commands against the server (without returning a response); +the `QueryExecutor` allows fetching resources and representations from the server. + +To use your custom resource, pass the fully-qualified class name (FQCN) to the `Keycloak::resource()` method. It provides you with an instance of your resource you can then work with: +```php +$keycloak = new Keycloak( + $_SERVER['KEYCLOAK_BASE_URL'] ?? 'http://keycloak:8080', + 'admin', + 'admin', +); + +$myCustomResource = $keycloak->resource(MyCustomResource::class); +$myCustomRepresentation = $myCustomResource->myCustomEndpoint(); +``` + ## Available Resources ### [Attack Detection](https://www.keycloak.org/docs-api/23.0.0/rest-api/index.html#_attack_detection_resource) | Endpoint | Response | API | diff --git a/examples/custom-resource.php b/examples/custom-resource.php new file mode 100644 index 0000000..c475d50 --- /dev/null +++ b/examples/custom-resource.php @@ -0,0 +1,43 @@ +queryExecutor->executeQuery( + new \Fschmtt\Keycloak\Http\Query( + '/my-custom-endpoint', + MyCustomRepresentation::class, + ) + ); + } +} + +$keycloak = new Keycloak( + $_SERVER['KEYCLOAK_BASE_URL'] ?? 'http://keycloak:8080', + 'admin', + 'admin', +); + +/** @var MyCustomResource $myCustomResource */ +$myCustomResource = $keycloak->resource(MyCustomResource::class); +$myCustomRepresentation = $myCustomResource->myCustomEndpoint(); diff --git a/src/Keycloak.php b/src/Keycloak.php index 71c6176..8df196a 100644 --- a/src/Keycloak.php +++ b/src/Keycloak.php @@ -14,6 +14,7 @@ use Fschmtt\Keycloak\Resource\Clients; use Fschmtt\Keycloak\Resource\Groups; use Fschmtt\Keycloak\Resource\Realms; +use Fschmtt\Keycloak\Resource\Resource; use Fschmtt\Keycloak\Resource\Roles; use Fschmtt\Keycloak\Resource\ServerInfo; use Fschmtt\Keycloak\Resource\Users; @@ -102,6 +103,17 @@ public function roles(): Roles return new Roles($this->commandExecutor, $this->queryExecutor); } + /** + * @param class-string $resource + * @return Resource + */ + public function resource(string $resource): Resource + { + $this->fetchVersion(); + + return new $resource($this->commandExecutor, $this->queryExecutor); + } + private function fetchVersion(): void { if ($this->version) {