Prisma PHPX
Prisma PHPX is a template system for Prisma PHP that is inspired by JSX and React.
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 example, to create a
SearchIcon
component,
you should create a file named
SearchIcon.php
in the
src/app/Lib/PHPX/GoogleIcons/SearchIcon.php
directory. The class name should match the file name.
It is important to note that you can have one initializer file for all your components. For example, you can follow a naming convention like
Accordion
for the main component. The related components should follow the same naming convention, such as
AccordionItem
,
AccordionTrigger
, and
AccordionContent
. These classes should be in the same file and start with the main component name, in this case,
Accordion
, followed by the specific component name.
The file can be located in any directory you desire, but following the naming convention is important. For example, you can place it in
src/app/Lib/PHPX/Components/Accordion.php
.
By default, the class constructor's props will receive the
children
property,
which represents the inner content of the component. You can also pass other props to the component, such as
class
and others.
The PHPX class provides three primary properties: $props
, $children
, and $class
. These properties store the sanitized versions of the component's attributes, content, and CSS classes, respectively. When extending the PHPX class, you can utilize these properties to meet your custom requirements.
-
$props
: The properties or attributes passed to the component. -
$children
: The children elements or content to be rendered within the component. -
$class
: The CSS class for custom styling. -
$attributesArray
: An array of attributes to be rendered as HTML attributes, useful when you want to spread all attributes to the component.
PHPX provides several methods that you can override to customize your components. The most important method is the constructor. When you extend the PHPX class, you should pass the props from your constructor if you plan to use any of the properties and methods provided by the PHPX class. You can override any of the methods to tailor your component to your needs. A common use case is the static init method, which you can use to register and retrieve information like dialog IDs or other data when the component is initialized. This information can then be shared with child components using the StateManager class, which is designed to facilitate information sharing within the application environment.
-
__construct(array $props = [])
: Constructor to initialize the component with the given properties. -
init(array $props = [])
: Registers or initializes any necessary components or settings. -
getMergeClasses()
: Combines and returns the CSS classes for the component, especially useful when working with dynamic TailwindCSS classes. -
getAttributes()
: Generates a string of HTML attributes from the provided props, ensuring no duplication of attributes. You can pass an array as the second argument to specify attributes to exclude, which will be removed from the final attributes string. -
render()
: Renders the component as an HTML string with the appropriate classes and attributes. -
__toString()
: Converts the object to its string representation by rendering it.
Note: A Prisma PHPX component is recognized only if it extends the PHPX class or implements the IPHPX interface. Otherwise, it will be ignored as a component. All components are registered in the settings/class-log.json
and settings/class-imports.json
files. If there are any conflicts or missing components, you can restart the server to re-register them automatically. When the server starts, these files are deleted and then recreated with all the components found in the project.
In the src/Lib/PHPX
directory, you will find the following files:
-
TemplateCompiler.php
: The main compiler for the PHPX template system. -
PHPX.php
: The base class that all your PHPX components should extend. -
IPHPX.php
: An interface that all PHPX components must implement. Note: If you extend the PHPX class, implementing this interface is not required. -
TwMerge.php
: A helper class for merging classes, particularly useful for dynamic TailwindCSS classes.
To import your component, use use Lib\PHPX\GoogleIcons\Search;
and then use the component as <Search />
.
If you have issues when importing components with the same name from different libraries, use an alias like use Lib\PHPX\GoogleIcons\Search as GoogleSearch;
and then use the component as <GoogleSearch />
.
For example, if you have a component named Search in two different libraries, you can import them as use Lib\PHPX\GoogleIcons\Search as GoogleSearch;
and use Lib\PHPX\LucideIcons\Search as LucideSearch;
and then use the components as <GoogleSearch />
and <LucideSearch />
.
The execution order of components starts from the outermost parent and proceeds to the innermost child.
By default, parent components are executed first, followed by the child components. This allows the parent to share props with its children, and the children can communicate back to the parent using the StateManager
class.
Default Execution Order
<?php
use Lib\PHPX\PHPXUI\{Accordion, AccordionItem, AccordionTrigger, AccordionContent};
?>
<Accordion>
<AccordionItem>
<AccordionTrigger>Prisma PHP is awesome!</AccordionTrigger>
<AccordionContent>Prisma PHPX is inspired by JSX and React.</AccordionContent>
</AccordionItem>
</Accordion>
- Accordion initialized
- AccordionItem initialized
- AccordionTrigger initialized
- AccordionContent initialized
In Prisma PHP, all tags must follow strict XML closing rules, similar to JSX:
- Valid:
<hr />
- Invalid:
<hr>
- Valid:
<br />
- Invalid:
<br>
- Valid:
<input type="text" />
- Invalid:
<input type="text">
- Valid:
<image src="image.jpg" />
- Invalid:
<image src="image.jpg">
Attributes must be enclosed in double quotes and follow strict XML rules:
- Valid:
<input required="true" />
- Invalid:
<input required />
- Valid:
<input type="text" id="input" />
- Invalid:
<input type="text" id=input />
When working with complex strings or code that needs to be escaped from XML or XAML processing, it is recommended to use <![CDATA[ ... ]]>
. This is particularly useful when displaying code or content that might otherwise be misinterpreted by the parser.
<![CDATA[
// Your complex code here
]]>
When using the <pre>
or <code>
tags, always escape the "<" character using HTML entities to prevent rendering issues during XML parsing.
When working with JSON data, you can use the json_encode()
function to convert the data to a JSON string. This function is useful when you need to pass data from PHP to JavaScript or store data in a JSON file. To prevent XSS attacks, use json_encode($data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT)
. This ensures that special characters are properly encoded, preventing the XML parser from misinterpreting them as HTML tags and avoiding rendering issues in the browser.
Explanation of JSON Encoding Options:
Constant | Description |
---|---|
JSON_HEX_TAG | Escapes < and > as \u003C and \u003E to prevent HTML injection. |
JSON_HEX_AMP | Escapes & as \u0026 to prevent breaking HTML attributes. |
JSON_HEX_APOS | Escapes ' (single quote) as \u0027 to prevent JavaScript issues. |
JSON_HEX_QUOT | Escapes " (double quote) as \u0022 to prevent breaking JSON inside HTML attributes. |
Use MainLayout::addFooterScript($accordionScript);
to add scripts to the footer dynamically.
Example usage of the heredoc and nowdoc syntax in PHP:
<<<HTML ... HTML;
is used for heredocs, while
<<<'HTML' ... HTML;
is used for nowdocs.
The key difference is that heredocs parse variables and escape sequences, whereas nowdocs treat the content as plain text and do not parse variables or escape sequences.
Use heredocs when you need to include variables or special characters, and nowdocs when you want to include raw, unprocessed text.
public function __construct(array $props = [])
{
parent::__construct($props);
$accordionScript = <<<HTML // Use <<<'HTML' for nowdocs
<script>
// Your JavaScript code here
</script>
HTML;
MainLayout::addFooterScript($accordionScript);
}
To create a component by inheriting the PHPX class, simply call the parent constructor and render method. Use the inherited methods to get attributes and classes, and return the HTML code as a string.
<?php
namespace Lib\PHPX\Components;
use Lib\PHPX\PHPX;
class Button extends PHPX
{
public function __construct(array $props = [])
{
parent::__construct($props);
}
public function render(): string
{
$attributes = $this->getAttributes([
'type' => 'button',
]);
$class = $this->getMergeClasses('bg-blue-500 p-2 rounded-md text-white hover:bg-blue-600');
return <<<HTML
<button class="$class" $attributes>
{$this->children}
</button>
HTML;
}
}
To share props from parent to child, you can pass the props to the child component. Using the StateManager
class makes this process easy and intuitive, allowing seamless sharing of information between parent and child components.
<?php
namespace Lib\PHPX\Components;
use Lib\PHPX\PHPX;
class Parent extends PHPX
{
public function __construct(array $props = [])
{
parent::__construct($props);
StateManager::setState('fromParent', 'Hello from Parent!');
}
public function render(): string
{
$fromChild = StateManager::getState('fromChild');
$attributes = $this->getAttributes();
$class = $this->getMergeClasses();
return <<<HTML
<div class="{$class}" {$attributes}>
<p>{$fromChild}</p>
{$this->children}
</div>
HTML;
}
}
class ParentChild extends PHPX
{
public function __construct(array $props = [])
{
parent::__construct($props);
StateManager::setState('fromChild', 'Hello from Child!');
}
public function render(): string
{
$fromParent = StateManager::getState('fromParent');
$attributes = $this->getAttributes();
$class = $this->getMergeClasses();
return <<<HTML
<div class="{$class}" {$attributes}>
<p>{$fromParent}</p>
{$this->children}
</div>
HTML;
}
}
In this example, the parent component shares its state with the child component using the StateManager
class. The child component can access the parent's state and vice versa.