Yoyo PHP Framework

repository·develop·Indexed 42 days ago

https://github.com/clickfwd/yoyo

A full-stack PHP framework for creating reactive, dynamic user interfaces using server-rendered HTML and htmx-like patterns. It allows developers to build interactive components with PHP classes and templates, featuring server-side state management, automatic DOM updates, and an event system for component communication without writing custom JavaScript.

Tokens
13.7K
Snippets
56
Records
60
Agent score
49%

What's inside Yoyo

  1. Trigger component actions with HTTP directives

    develop

    An action is a request to a component method to trigger a re-render. By default, Yoyo calls the render() method. You can specify explicit HTTP methods using these directives:

    • yoyo:get
    • yoyo:post
    • yoyo:put
    • yoyo:patch
    • yoyo:delete

    All components automatically listen for the refresh event to trigger the render action.

    <!-- Calling the 'helpful' method via GET -->
    <button yoyo:on="click" yoyo:get="helpful">Found Helpful</button>
  2. Use public properties for reactive component state

    develop

    In Yoyo dynamic components, all public properties in the component class are automatically available to the view and tracked for updates.

    Constraints:

    • Supported types: string, int, array, and boolean.
    • Security Warning: Do not store sensitive information in public properties, as they are sent in component requests to maintain synchronization.

    To initialize properties before the render method runs, use the mount() method.

    class HelloWorld extends Component
    {
        public $message;
    
        public function mount()
        {
            $this->message = 'Hello World!';
        }
    }
  3. Use Yoyo Twig variables and event functions

    develop

    Yoyo provides several specialized features within Twig templates:

    Re-rendering state

    Use the spinning variable to detect if a component is currently being re-rendered.

    {% if spinning %}
      Component updated
    {% endif %}

    Event Emission

    All event methods are available as functions to emit events from the component:

    • emit('eventName', payload): Emits an event.
    • emitUp('eventName', payload): Emits an event up the component tree.
    • emitSelf('eventName', payload): Emits an event to itself.
    • emitTo('component-name', 'eventName', payload): Emits an event to a specific component.

    Example:

    {{ emit('eventName', {'foo':'bar'}) }}

    Computed Properties

    If a component defines a getter method following the pattern get{PropertyName}Property(), you can access it in Twig using this.{property_name} (snake_case).

    class HelloWorld extends Component
    {
        public $message = 'Hello World!';
    
        public function getHelloWorldProperty()
        {
            return $this->message;
        }
    }
    <div quite>
        <h1>{{ this.hello_world }}</h1>
        <!-- Outputs: Hello World! -->
    </div>
  4. Communicate between components using Events

    develop

    Yoyo provides a robust event system for communication between components on the same page. Events can be emitted from component methods or templates and listened to by other components or JavaScript.

    Emitting Events (PHP)

    • emit('eventName', ...$args): Emits to all Yoyo components.
    • emitUp('eventName', ...$args): Emits to parent components only.
    • emitTo('componentName', 'eventName', ...$args): Emits to a specific component by name or CSS selector (selectors do not support arguments).
    • emitSelf('eventName', ...$args): Emits to the current component.

    Listening for Events (PHP)

    Register listeners in a component using the protected $listeners property. The key is the event name, and the value is the method name.

    Listening for Events (JavaScript)

    Use Yoyo.on('eventName', callback) to listen for component-emitted events in the browser.

    Dispatching Events (JavaScript)

    Use Yoyo.dispatch('eventName', data) to trigger events globally, or Yoyo.dispatchTo('componentName', 'eventName', data) for specific components.

    // Emitting from a method
    $this->emit('counter-updated', $count);
    
    // Listening in a component
    protected $listeners = ['counter-updated' => 'showNewCount'];
    
    protected function showNewCount($count)
    {
        $this->message = "The new count is: $count";
    }
    // Listening in JS
    Yoyo.on('productAddedToCart', id => {
        alert('ID: ' + id);
    });
    
    // Dispatching from JS
    Yoyo.dispatch('post-created', { postId: 2 });
  5. How Yoyo components work

    develop

    Yoyo uses a server-side component model to create reactive interfaces.

    1. Rendering: Components are rendered on page load using yoyo_render().
    2. Interaction: When a user interacts with a component (e.g., clicking a button with a yoyo:get attribute), a request is sent to the configured Yoyo url.
    3. Update: Yoyo processes the request on the server, updates the component state, and sends back an HTML partial.
    4. Reactivity: The browser receives the partial and updates the DOM without a full page reload.

    Components consist of a PHP Class (handling logic and state) and a Template (handling the HTML markup).

    // Component Class
    class Counter extends Component
    {
        public $count = 0;
        protected $props = ['count']; // Persists 'count' across requests
    
        public function increment()
        {
            $this->count++;
        }
    }
    <!-- Component Template -->
    <div>
        <button yoyo:get="increment">+</button>
        <span><?php echo $count; ?></span>
    </div>
  6. Manage view data and computed properties

    develop

    View Data

    To send data to a view that isn't a public property:

    • Override render() and pass an array as the second argument to $this->view().
    • Use $this->set('key', 'value') inside any action.

    Computed Properties

    Define methods following the pattern get{PropertyName}Property(). These are accessible in templates as $this->{property_name}.

    • Caching: Computed property outputs are cached within the same request.
    • Clearing Cache: Use $this->forgetComputed(), $this->forgetComputed($property), or $this->forgetComputedWithArgs($property, ...$args) to invalidate the cache.
    class HelloWorld extends Component
    {
        public $message = 'Hello World!';
        
        // Accessible as $this->hello_world in template
        public function getHelloWorldProperty()
        {
            return $this->message;
        }
    }
  7. Configure Yoyo with TwigViewProvider

    develop

    When using Twig, initialize Yoyo with your project configuration (URL, scripts path, and namespace) and register a callback for registerViewProvider that returns a TwigViewProvider instance wrapping your Twig environment. Additionally, add YoyoTwigExtension to your Twig environment to enable Yoyo-specific Twig functions.

    use Clickfwd\
    Yoyo\
    Twig\
    YoyoTwigExtension;
    use Clickfwd\
    Yoyo\
    ViewProviders\
    TwigViewProvider;
    use Clickfwd\
    Yoyo\
    Yoyo;
    use Twig\
    Environment;
    use Twig\
    Loader\
    FilesystemLoader;
    
    $yoyo = new Yoyo();
    
    $yoyo->configure([
      'url' => 'yoyo',
      'scriptsPath' => APP_PATH.'/app/resources/assets/js/',
      'namespace' => 'App\\Yoyo\\',
    ]);
    
    $loader = new FilesystemLoader([
      APP_PATH.'/resources/views',
      APP_PATH.'/resources/views/yoyo',
    ]);
    
    $twig = new Environment($loader, [
      'cache' => APP_PATH.'/../cache',
      'auto_reload' => true,
    ]);
    
    // Add Yoyo's Twig Extension
    $twig->addExtension(new YoyoTwigExtension());
    
    // Register Twig view provider for Yoyo
    $yoyo->registerViewProvider(function() use ($twig) {
      return new TwigViewProvider($twig);
    });
  8. Toggle CSS classes and attributes during component updates

    develop

    You can modify an element's appearance or state while a component is updating using Yoyo modifiers in your HTML templates.

    Toggling CSS Classes

    Use the .class modifier to add space-separated class names. Use .class.remove to remove specific classes.

    Toggling Attributes

    Use the .attr modifier to add or remove HTML attributes (e.g., disabled).

    <!-- Add classes during update -->
    <button yoyo:post="submit" yoyo:spinning.class="text-gray-300">
        Submit
    </button>
    
    <!-- Remove classes during update -->
    <button yoyo:post="submit" yoyo:spinning.class.remove="bg-blue-200" class="bg-blue-200">
        Submit
    </button>
    
    <!-- Add attributes during update -->
    <button yoyo:post="submit" yoyo:spinning.attr="disabled">
        Submit
    </button>
  9. Load Yoyo assets in Twig

    develop

    First, copy yoyo.js from /vendor/clickfwd/yoyo/src/assets/js/yoyo.js to your project's public assets directory. Then, include the necessary scripts in your Twig template's <head> tag using the yoyo_scripts() function.

    {{ yoyo_scripts() }}
  10. Install Yoyo in Phalcon Framework

    develop

    To use Yoyo with the Phalcon framework, you must register the YoyoPhalconServiceProvider in your Dependency Injection (DI) container, add a specific route for Yoyo, and ensure your controllers inherit from Clickfwd\Yoyo\PhalconController.

    // Register the service provider
    $di->register(new \Clickfwd\Yoyo\YoyoPhalconServiceProvider());
    
    // Add the Yoyo router
    $router->add('/yoyo', [
        'controller' => 'yoyo',
        'action' => 'handle',
    ]);
  11. Configure component props for persistence

    develop

    To ensure specific variables are included in every request for persistence:

    • Dynamic Components: Define a protected $props array containing the names of the variables to track.
    • Anonymous Components: Use the yoyo:props attribute on the root node with a comma-separated list of variable names.
    // Dynamic Component
    class Counter extends Component
    {
        public $count = 0;
        protected $props = ['count'];
    
        public function increment() { $this->count++; }
    }
    <!-- Anonymous Component -->
    <div yoyo:props="count">
        <button yoyo:val.count="<?php echo $count + 1; ?>" >+</button>
    </div>
  12. Integrate Yoyo with Twig

    develop

    To use Yoyo with the Twig templating engine, install both clickfwd/yoyo and twig/twig via Composer. You must configure Yoyo to use a TwigViewProvider and register the YoyoTwigExtension within your Twig environment. This setup ensures Yoyo can render components using Twig templates and provides necessary Twig functions.

    composer require clickfwd/yoyo
    composer require twig/twig