Prisma PHPX

Prisma PHPX is a template system for PHP that is inspired by JSX and React.

npx create-prisma-php-app@template

Example Usage: The following template demonstrates how to use Prisma PHPX for creating reusable components. Use this as a foundation for building your own custom components.

To maintain order and consistency, create a directory in src/app/Lib/PHPX/DirectoryName/ClassName.php. This convention helps in organizing and managing your components effectively.

For instance, if you want to create a SearchIcon component, you should create a file named SearchIcon.php in the src/app/Lib/PHPX/GoogleIcons/SearchIcon.php directory. Notice that a directory named GoogleIcons is created, and within it, a file named SearchIcon.php. The file name must match the class name to comply with the Composer autoloading system, which will replace the ComponentTemplate class in your component.

<?php

  namespace Lib\PHPX;
  
  use Lib\PHPX\IPHPX;
  use Lib\PHPX\Utils;
  
  /**
   * ComponentTemplate class represents a base component for rendering HTML elements with customizable properties.
   * 
   * It provides a structured way to define reusable UI components such as cards, with support for dynamic class 
   * and attribute merging.
   */
  class ComponentTemplate implements IPHPX
  {
      /**
       * @var array<string, mixed> The properties or attributes passed to the component.
       */
      private array $props;
  
      /**
       * @var mixed The children elements or content to be rendered within the component.
       */
      private mixed $children;
  
      /**
       * @var string The CSS class for custom styling.
       */
      private string $class;
  
      /**
       * @var string Stores the precomputed CSS classes for the component.
       */
      private string $computedClass;
  
      /**
       * Constructor to initialize the component with the given properties.
       * 
       * @param array<string, mixed> $props Optional properties to customize the component.
       */
      public function __construct(array $props = [])
      {
          $this->props = $props;
          $this->children = $props['children'] ?? '';
          $this->class = $props['class'] ?? '';
  
          // Precompute the static classes once during construction
          $this->computedClass = $this->getComputedClasses();
  
          // Optionally, execute an initialization function if passed
          $this->executeFunction('onInit', [$this->props]);
      }
  
      /**
       * Registers or initializes any necessary components or settings. (Placeholder method).
       */
      public static function init(): void
      {
          // Register the component or any necessary initialization
      }
  
      /**
       * Combines and returns the CSS classes for the component.
       * 
       * @return string The merged CSS class string.
       */
      private function getComputedClasses(): string
      {
          $baseClass = ''; // Define any base classes if necessary
          return Utils::mergeClasses($baseClass, $this->class);
      }
  
      /**
       * Generates and returns a string of HTML attributes from the provided props.
       * Excludes 'class' and 'children' props from being added as attributes.
       * 
       * @return string The generated HTML attributes.
       */
      private function getAttributes(): string
      {
          // Filter out 'class' and 'children' props
          $filteredProps = array_filter($this->props, function ($key) {
              return !in_array($key, ['class', 'children']);
          }, ARRAY_FILTER_USE_KEY);
  
          // Build attributes string by escaping keys and values
          $attributes = [];
          foreach ($filteredProps as $key => $value) {
              $escapedKey = htmlspecialchars($key, ENT_QUOTES, 'UTF-8');
              $escapedValue = htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
              $attributes[] = "$escapedKey='$escapedValue'";
          }
  
          return implode(' ', $attributes);
      }
  
      /**
       * Executes a callable function passed in the props.
       * 
       * @param string $propKey The key of the prop to check for a callable.
       * @param array $params Parameters to pass to the function.
       * @return mixed|null The result of the function execution, or null if not callable.
       */
      private function executeFunction(string $propKey, array $params = [])
      {
          if (isset($this->props[$propKey]) && is_callable($this->props[$propKey])) {
              // Execute the function and pass the parameters
              return call_user_func_array($this->props[$propKey], $params);
          }
  
          return null;
      }
  
      /**
       * Renders the component as an HTML string with the appropriate classes and attributes.
       * Also, allows for dynamic children rendering if a callable is passed.
       * 
       * @return string The final rendered HTML of the component.
       */
      public function render(): string
      {
          $attributes = $this->getAttributes();
          $class = $this->computedClass;
  
          // Handle children being a callable (e.g., for dynamic content)
          $childrenContent = is_callable($this->children)
              ? call_user_func($this->children, $this->props) // Pass props to children if callable
              : $this->children;
  
          // Execute a render hook function if defined
          $this->executeFunction('onRender', [$this, $this->props]);
  
          return "<div class='$class' $attributes>$childrenContent</div>";
      }
  
      /**
       * Converts the object to its string representation by rendering it.
       *
       * @return string The rendered HTML output of the component.
       */
      public function __toString(): string
      {
          return $this->render();
      }
  }