2.3. Composite

2.3.1. Propósito

Para tratar de manera uniforme a objetos individuales y a los compuestos.

2.3.2. Ejemplos

  • Una instancia de una clase formulario maneja todos sus elementos de formulario como una única instancia del formulario, cuando se llama a render(), se ejecuta a través de todos sus elementos hijo y llama a render() en ellos

2.3.3. Diagrama UML

Alt Composite UML Diagram

2.3.4. Código

Puedes encontrar el código en GitHub

Renderable.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite;
 6
 7interface Renderable
 8{
 9    public function render(): string;
10}

Form.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite;
 6
 7/**
 8 * The composite node MUST extend the component contract. This is mandatory for building
 9 * a tree of components.
10 */
11class Form implements Renderable
12{
13    /**
14     * @var Renderable[]
15     */
16    private array $elements;
17
18    /**
19     * runs through all elements and calls render() on them, then returns the complete representation
20     * of the form.
21     *
22     * from the outside, one will not see this and the form will act like a single object instance
23     */
24    public function render(): string
25    {
26        $formCode = '<form>';
27
28        foreach ($this->elements as $element) {
29            $formCode .= $element->render();
30        }
31
32        return $formCode . '</form>';
33    }
34
35    public function addElement(Renderable $element)
36    {
37        $this->elements[] = $element;
38    }
39}

InputElement.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite;
 6
 7class InputElement implements Renderable
 8{
 9    public function render(): string
10    {
11        return '<input type="text" />';
12    }
13}

TextElement.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite;
 6
 7class TextElement implements Renderable
 8{
 9    public function __construct(private string $text)
10    {
11    }
12
13    public function render(): string
14    {
15        return $this->text;
16    }
17}

2.3.5. Test

Tests/CompositeTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite\Tests;
 6
 7use DesignPatterns\Structural\Composite\Form;
 8use DesignPatterns\Structural\Composite\TextElement;
 9use DesignPatterns\Structural\Composite\InputElement;
10use PHPUnit\Framework\TestCase;
11
12class CompositeTest extends TestCase
13{
14    public function testRender()
15    {
16        $form = new Form();
17        $form->addElement(new TextElement('Email:'));
18        $form->addElement(new InputElement());
19        $embed = new Form();
20        $embed->addElement(new TextElement('Password:'));
21        $embed->addElement(new InputElement());
22        $form->addElement($embed);
23
24        // This is just an example, in a real world scenario it is important to remember that web browsers do not
25        // currently support nested forms
26
27        $this->assertSame(
28            '<form>Email:<input type="text" /><form>Password:<input type="text" /></form></form>',
29            $form->render()
30        );
31    }
32}