Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
index.md 13.61 KiB
collections: 
    - name: primary_navigation
      next: docs/index
content_type: html
layout: dm:page
register_stylesheets:
    - docs-page-homepage.css
title: Resonance
description: >
    PHP Framework designed from the ground up to facilitate 
    interoperability and messaging between services in your infrastructure and
    beyond.

Resonance

Build Web Applications with AI and ML Capabilities

Designed from the ground up to facilitate interoperability and messaging between services in your infrastructure and beyond.

Takes full advantage of asynchronous PHP. Built on top of Swoole.

Get Started
  • 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.

    Learn More
    #[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();
    }
    
    }
  • Artificial Intelligence

    Integrate your application with self-hosted open-source LLMs.

    Use your own Machine Learning models in production.

    Learn More
    class LlamaCppGenerate
    {
    public function __construct(protected LlamaCppClientInterface $llamaCppClient)
    {
    }
    public function doSomething(): void
    {
        $request = new LlamaCppCompletionRequest('How to make a cat happy?');
    
        $completion = $this->llamaCppClient->generateCompletion($request);
    
        foreach ($completion as $token) {
            // ...
        }
    }
    
    }
  • 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.

    Learn More
    #[RespondsToWebSocketJsonRPC(JsonRPCMethod::Echo)]
    #[Singleton(collection: SingletonCollection::WebSocketJsonRPCResponder)]
    final readonly class EchoResponder extends WebSocketJsonRPCResponder
    {
    public function getConstraint(): Constraint
    {
    return new StringConstraint();
    }
    public function onRequest(
        WebSocketAuthResolution $webSocketAuthResolution,
        WebSocketConnection $webSocketConnection,
        RPCRequest $rpcRequest,
    ): void {
        $webSocketConnection->push(new RPCResponse(
            $rpcRequest,
            $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.

    Learn More
    #[RespondsToHttp(
    method: RequestMethod::GET,
    pattern: '/',
    routeSymbol: HttpRouteSymbol::Homepage,
    )]
    #[Singleton(collection: SingletonCollection::HttpResponder)]
    readonly class Homepage implements HttpResponderInterface
    {
    public function respond(
    ServerRequestInterface $request,
    ResponseInterface response ): TwigTemplate { return new TwigTemplate(request, $response, '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.

    Learn More
    #[ListensTo(HttpServerStarted::class)]
    #[Singleton(collection: SingletonCollection::EventListener)]
    final readonly class InitializeErrorReporting extends EventListener
    {
    public function handle(object event): void { // ... } }</code></pre> </li> <li class="formatted-content homepage__example"> <h2 class="homepage__example__title"> Powerful Dependency Injection </h2> <div class="homepage__example__description"> <p> Your project's files are indexed when the application  starts. Relations between services are then set up  by using attributes. </p> <p> There is no need for an elaborate configuration of  services. Everything is handled by the attributes. </p> <a  class="homepage__cta homepage__cta--example" href="/docs/features/dependency-injection/" > Learn More </a> </div> <pre class="homepage__example__code fenced-code"><code  class="language-php" data-controller="hljs" data-hljs-language-value="php" >#[Singleton(provides: LoggerInterface::class)] readonly class Logger implements LoggerInterface { public function log(level, string|Stringable $message, array context = []): void { // ... } }</code></pre> </li> <li class="formatted-content homepage__example"> <h2 class="homepage__example__title"> Promises in PHP </h2> <div class="homepage__example__description"> <p> Resonance provides a partial implementation of  Promise/A+ spec to handle various asynchronous tasks. </p> <p> </p> <a  class="homepage__cta homepage__cta--example" href="/docs/features/swoole-futures/" > Learn More </a> </div> <pre class="homepage__example__code fenced-code"><code  class="language-php" data-controller="hljs" data-hljs-language-value="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.

    Learn More
    #[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);
    }
    
    public function toGraphQLField(): array
    {
        return [
            'type' => new ListOfType($this->blogPostType),
            'resolve' => $this->resolve(...),
        ];
    }
    
    }