3

All I'm trying to do is generate a form with text input fields and buttons in the coding style below. The text input fields are working fine. However, the radio button class is not. The radio button class should have a title for the group and the addOption function should show each option with a radio button. When I test my code, there's no title "Number of Scoops" and only one radio button for "Three Scoops" and not for "One Scoop" and "Two Scoops." What am I doing wrong? Here's my code:

IceCreamForm.php:

<?php

require_once 'Form.php';
require_once 'RadioButton.php';
require_once 'TextInput.php';
require_once 'Validator.php';

$form = new Form();

$form -> addInput(new TextInput("First Name: ", "firstName"));
$form -> addInput(new TextInput("Last Name: ", "lastName"));
$form -> addInput(new TextInput("Ice Cream Flavor: ", "iceCreamFlavor"));

$radio = new RadioButton("Number of Scoops: ");
$radio -> addOption("One Scoop", "one");
$radio -> addOption("Two Scoops", "two");
$radio -> addOption("Three Scoops", "three");
$form -> addInput($radio);

echo $form -> generateHTML();

Form.php:

<?php

class Form
{
    const GET = "GET";
    const POST = "POST";
    private $action = "someLocation.php";
    private $inputs = array();
    private $method = "POST";
    public $form = "";
    public $name = "";

    function __construct()
    {

    }

    function addInput(TextInput $input)
    {
        $this -> inputs[] = $input;
    }

    function getAction(): string
    {
        return $this -> action;
    }

    function getMethod(): string
    {
        return $this -> method;
    }

    function setAction(string $action)
    {
        $this -> action = $action;
        return $this;
    }

    function setMethod(string $method)
    {
        $this -> method = $method;
        return $this;
    }

    function set($param, $value)
    {
        $this -> $param = $value;
    }

    function generateHTML(): string
    {
        $this -> form = '<form action="' . $this -> getAction() . '" 
        method="' . $this -> getMethod() . '">';
        foreach ($this -> inputs as $input)
        {
            $this -> form .= $input -> generateHTML();
        }

        $this -> form .= '</form>';

        return $this -> form;
    }
}

TextInput.php:

<?php

class TextInput
{
    const TYPE = "text";
    private static $REQUIRED = "REQUIRED";
    private $defaultValue;
    private $id;
    private $label;
    private $name;
    private $onNewLine;
    private $required = false;
    private $type;

    function __construct($label = "", $name = "", $defaultValue = "", $id = "", $onNewLine = "", $required = false, $type = self::TYPE)
    {
        $this -> defaultValue = $defaultValue;
        $this -> id = $id;
        $this -> label = $label;
        $this -> name = $name;
        $this -> onNewLine = $onNewLine;
        $this -> required = $required;
        $this -> type = $type;
    }

    public function generateHTML():string
    {
        $req = "";

        if ($this -> required == true)
        {
            $req = self::$REQUIRED;
        }

        return "<label>$this->label</label><input id='$this->id' type='$this->type' name='$this->name' onNewLine='$this->onNewLine' $req/><br/>";
    }
}

RadioButton.php:

<?php

require_once 'TextInput.php';

class RadioButton extends TextInput
{
    const TYPE2 = "radio";
    private $selected = false;
    private $type;

    function __construct($selected = false, $type = self::TYPE2)
    {
        $this -> selected = $selected;
        $this -> type = $type;
    }

    function addOption(string $label, string $value)
    {
        $this -> label = $label;
        $this -> value = $value;
    }

    public function generateHTML():string
    {
        $req = "";

        if ($this -> required == true)
        {
            $req = self::$REQUIRED;
        }

        return "<label>$this->label</label><input id='$this->id' type='$this->type' value='$this->value' onNewLine='$this->onNewLine' $req/><br/>";
    }
}

1 Answer 1

2
...there's no title "Number of Scoops"...

Because your RadioButton constructor doesn't set a title. Only $selected and $type.

...and only one radio button for "Three Scoops" and not for 
"One Scoop" and  "Two Scoops."...

Because your addOption method overwrites the previously set label and value. Try adding them to an array.

function addOption(string $label, string $value) {
    $this->options[] = [
        'label' => $label,
        'value' => $value,
    ];
}

Then in your generateHTML()...

return join('', array_map(function($item) {
    return sprintf('<label>%s</label> <input type="radio" value="%s">', $item['label'], $item['value']);
}, $this->options));
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you! I understand the title part, and was able to fix that. I'm not quite understanding the addOption array fix. What would a code snippet of that look like?
An example would be your own Form classes addInput() method. You would also need to iterate over them in generateHTML()
So, I have function addOption(string $label, string $value) { $this -> label = $label; $this -> value = $value; $this -> options[] = $label; }, but would I put foreach ($this -> options as $label) { $this -> radiobutton .= $label -> generateHTML(); } in the generatehtml() method? Is that what the iteration would look like?
Also, you should utilize the name attribute for the radio button options, lest the radio buttons become disjointed. I recommend having the RadioButton constructor accept a string for the name to be assigned to $this->name, making the instance variable TextInput::$name protected (so it can be used by RadioButton) and then in the lambda function in RadioButton::generateHtml(), add name="%s" with an extra parameter to sprintf with the value $this->name.
Yes, you should use the name attribute. I removed unnecessary code for brevity. I would also recommend using a framework like laravel or symfony instead of writing this yourself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.