Composite Pattern

Purpose

To treat a group of objects the same way as a single instance of the object.

Examples

A form class instance handles all its form elements like a single instance of the form, when render() is called, it subsequently runs through all its child elements and calls render() on them

UML


Code

Renderable


namespace DesignPatterns\Structural\Composite;

interface Renderable
{
    public function render(): string;
}

Form


namespace DesignPatterns\Structural\Composite;

/**
* The composite node MUST extend the component contract. This is mandatory for building
* a tree of components.
*/
class Form implements Renderable
{
    /**
     * @var Renderable[]
     */
     private array $elements;

    /**
     * runs through all elements and calls render() on them, then returns the complete representation
     * of the form.
     * 
     * from the outside, one will not see this and the form will act like a single object instance
     */
     public function render(): string
     {
         $formCode = '
'; foreach ($this->elements as $element) { $formCode .= $element->render(); } return $formCode . '
'; } public function addElement(Renderable $element) { $this->elements[] = $element; } }

InputElement


namespace DesignPatterns\Structural\Composite;

class InputElement implements Renderable
{
    public function render(): string
    {
        return '';
    }
}

TextElement


namespace DesignPatterns\Structural\Composite;

class TextElement implements Renderable
{
    public function __construct(private string $text)
    {
    }

    public function render(): string
    {
        return $this->text;
    }
}

Tests


public function testRender()
{
    // Start building form (1st)
    $form = new Form();
    $form->addElement(new TextElement('Email:'));
    $form->addElement(new InputElement());

    // Build another form (2nd)
    $embed = new Form();
    $embed->addElement(new TextElement('Password:'));
    $embed->addElement(new InputElement());

    // Attach 2nd form to 1st form
    $form->addElement($embed);

    // This is just an example, in a real world scenario it is 
    // important to remember that web browsers do not
    // currently support nested forms

    $this->assertSame(
        '
Email:Password:
', $form->render() ); }

Ready to bring your vision to life?

We believe in excellence, empathy, integrity, and transparency throughout the process. Our goal is to build fast, responsive websites that not only perform but also reflect your values and vision.