diff --git a/README.md b/README.md index 6f6b7593e079afd778738e00cabe4f168ac3af20..40bab8016958f90876a45dce68fac4454d7d1314 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,185 @@ # Resonance +[Documentation](https://resonance.distantmagic.com/) + ## About -PHP Framework designed from the ground up to facilitate interoperability and +Designed from the ground up to facilitate interoperability and messaging between services in your infrastructure and beyond. -Takes full advantage of asynchronous PHP. +Provides AI capabilities. + +Takes full advantage of asynchronous PHP. Built on top of +Swoole. + +## Features + +### Chat with Open-Source LLMs + +Create prompt controllers to directly answer user's prompts. + +LLM takes care of determining user's intention, you can focus on taking an +appropriate action. + +```php +#[RespondsToPromptSubject( + action: 'adopt', + subject: 'cat', +)] +#[Singleton(collection: SingletonCollection::PromptSubjectResponder)] +readonly class CatAdopt implements PromptSubjectResponderInterface +{ + public function respondToPromptSubject(PromptSubjectRequest $request, PromptSubjectResponse $response): void + { + // Pipes message through WebSocket... + + $response->write("Here you go:\n\n"); + $response->write(" |\_._/|\n"); + $response->write(" | o o |\n"); + $response->write(" ( T )\n"); + $response->write(" .^`-^-`^.\n"); + $response->write(" `. ; .`\n"); + $response->write(" | | | | |\n"); + $response->write(" ((_((|))_))\n"); + $response->end(); + } +} +``` + +### Asynchronous Where it Matters + +Respond asynchronously to incoming RPC or WebSocket +messages (or both combined) with little overhead. + +You can set up all the asynchronous features using +attributes. No elaborate configuration is needed. + +```php +#[RespondsToWebSocketRPC(RPCMethod::Echo)] +#[Singleton(collection: SingletonCollection::WebSocketRPCResponder)] +final readonly class EchoResponder extends WebSocketRPCResponder +{ + public function getConstraint(): Constraint + { + return new StringConstraint(); + } + + public function onRequest( + WebSocketAuthResolution $webSocketAuthResolution, + WebSocketConnection $webSocketConnection, + RPCRequest $rpcRequest, + ): void { + $webSocketConnection->push(new RPCResponse( + $rpcRequest->requestId, + $rpcRequest->payload, + )); + } +} +``` + +### Simple Things Remain Simple + +Writing HTTP controllers is similar to how it's done in +the synchronous code. + +Controllers have new exciting features that take +advantage of the asynchronous environment. + +```php +#[RespondsToHttp( + method: RequestMethod::GET, + pattern: '/', + routeSymbol: HttpRouteSymbol::Homepage, +)] +#[Singleton(collection: SingletonCollection::HttpResponder)] +readonly class Homepage implements HttpResponderInterface +{ + public function respond(Request $request, Response $response): TwigTemplate + { + return new TwigTemplate('website/homepage.twig'); + } +} +``` + +### Consistency is Key + +You can keep the same approach to writing software +no matter the size of your project. + +There are no growing central configuration files +or service dependencies registries. Every relation +between code modules is local to those modules. + +```php +#[ListensTo(HttpServerStarted::class)] +#[Singleton(collection: SingletonCollection::EventListener)] +final readonly class InitializeErrorReporting extends EventListener +{ + public function handle(object $event): void + { + // ... + } +} +``` + +### Promises in PHP + +Resonance provides a partial implementation of +Promise/A+ spec to handle various asynchronous tasks. + +```php +$future1 = new SwooleFuture(function (int $value) { + assert($value === 1); + + return $value + 2; +}); + +$future2 = $future1->then(new SwooleFuture(function (int $value) { + assert($value === 3); + + return $value + 4; +})); + +assert($future2->resolve(1)->result === 7); +``` + +### GraphQL Out of the Box + +You can build elaborate GraphQL schemas by using just +the PHP attributes. + +Resonance takes care of reusing SQL queries and +optimizing the resources' usage. + +All fields can be resolved asynchronously. + +```php +#[GraphQLRootField( + name: 'blogPosts', + type: GraphQLRootFieldType::Query, +)] +#[Singleton(collection: SingletonCollection::GraphQLRootField)] +final readonly class Blog implements GraphQLFieldableInterface +{ + public function __construct( + private DatabaseConnectionPoolRepository $connectionPool, + private BlogPostType $blogPostType, + ) {} + + public function resolve(): GraphQLReusableDatabaseQueryInterface + { + return new SelectBlogPosts($this->connectionPool); + } -Built on top of Swoole. + public function toGraphQLField(): array + { + return [ + 'type' => new ListOfType($this->blogPostType), + 'resolve' => $this->resolve(...), + ]; + } +} +``` ## License diff --git a/composer.json b/composer.json index e29f77ed2a654382412bb0223ec59479382e231f..a9d6bf49c9ecab31753fa5f84463683d7d6f1d41 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "distantmagic/resonance", - "description": "PHP SaaS Framework", + "description": "PHP Framework with AI capabilities.", "type": "library", "license": "MIT", "autoload": { diff --git a/docs/pages/index.md b/docs/pages/index.md index 4d48cceee4e0dcacd96180e18cd7e53c6b530dce..cd0fc5e27b5d6f6c25ae227f379db64fba690a3a 100644 --- a/docs/pages/index.md +++ b/docs/pages/index.md @@ -23,10 +23,11 @@ description: > messaging between services in your infrastructure and beyond. </p> <p> - Takes full advantage of asynchronous PHP. + Provides AI capabilities. </p> <p> - Built on top of Swoole. + Takes full advantage of asynchronous PHP. Built on top of + Swoole. </p> <a class="homepage__cta" @@ -240,8 +241,7 @@ final readonly class InitializeErrorReporting extends EventListener { // ... } -} -</code></pre> +}</code></pre> </li> <li class="formatted-content homepage__example"> <h2 class="homepage__example__title">