Как визуализировать теги fieldset и легенды только один раз (для вывода 3 переключателей) - PullRequest
0 голосов
/ 30 октября 2019

У меня есть php-файл конфигурации, в котором я установил массив с атрибутами для 3 переключателей. В классе Radio у меня есть метод с именем render, который должен выводить переключатели. Переключатели должны быть размещены в теге html fieldset. Проблема, я получаю теги fieldset и legend для каждой кнопки-переключателя. Но я хочу, чтобы переключатели были встроены в 1 набор полей и 1 легенду. Я застрял.

Это конфигурация массива:

<?php
 $formConf = [
'kraken' => [
    'type' => 'radio',
    'id' => 'kraken',
    'name' => 'monster',
    'label' => 'Kraken',
    'radio' => 'checked'
],

'sasquatch' => [
    'type' => 'radio',
    'id' => 'sasquatch',
    'name' => 'monster',
    'label' => 'Sasquatch',
    'radio' => ''
],

'mothman' => [
    'type' => 'radio',
    'id' => 'mothman',
    'name' => 'monster',
    'label' => 'Mothman',
    'radio' => ''
]];

Вот класс Radio:

class Radio extends Input {

protected $radio = ''; 
protected $legend = 'Choose your favorite monster';

public function __construct(array $opts)
{
    parent::__construct($opts);

    $this->type = 'radio';

    if (!isset($opts['radio']) || $opts['radio'] === '' || $opts['radio'] == null)  {
        $this->radio = '';
        }
    elseif (isset($opts['radio'])) {
        $this->radio = $opts['radio'];    
    } 
}

Этот метод должен генерировать теги html:

public function render() : string
{        
    $out = '';
    $out .= '<fieldset>';
    $out .= '<legend>Choose your monster</legend>';
    $out .= '<input type="' . $this->type . '"';
    $out .= $this->renderRadioChecked();
    $out .= '<label for="' . $this->id . '"' . '>';
    $out .= $this->label . '</label>';
    $out .= '<br/>';
    $out .= '</fieldset>';

    return $out;        
}

protected function renderRadioChecked() 
{
    $out = '';
    if ($this->radio == '') {
    $out .= 'id="' . $this->id . '"' . 'name="' . $this->name . '"' . '>';
        } else {
            $out .= 'id="' . $this->id . '"' . 'name="' . $this->name . '"' . ' checked' . '>';
        }
        return $out;
    }

Ожидаемый результат должен быть:

<fieldset>
<legend>Choose your favorite monster</legend>

<input type="radio" id="kraken" name="monster">
<label for="kraken">Kraken</label><br/>

<input type="radio" id="sasquatch" name="monster" checked>
<label for="sasquatch">Sasquatch</label><br/>

<input type="radio" id="mothman" name="monster">
<label for="mothman">Mothman</label>
</fieldset>

Полная версия с переключателями можно посмотреть здесь: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset

Примечание: у меня уже есть форматег с другими тегами HTML на странице индекса. Вот почему я могу генерировать только набор полей, как указано здесь.

1 Ответ

0 голосов
/ 30 октября 2019

Я бы удалил html fieldset, так как это не элемент переключателя. Я мог бы подумать о том, чтобы сделать урок формы и внедрить радио в это. Таким образом, чтобы получить несколько переключателей, после удаления html fieldset зациклите класс переключателей ИЛИ вы можете просто позволить классу переключателей создавать более одной переключателя за раз:

class Radio extends Input
{
    protected $data;

    public function __construct(array $opts)
    {
        parent::__construct($opts);
        # The type is irrelevant since this class is a radio, the type is already known.
        # I would just assign the array to a storage variable
        if(empty($opts)) {
            $this->data = false;
        }
        else {
            # I would make sure the array is going to be consistent
            $this->data = (isset($opts['radio']))? [$opts] : $opts;
        } 
    }

    public function render() : string
    {
        # May as well stop here if empty
        if(empty($this->data))
            return false;
        # Loop your data array
        foreach($this->data as $radio) {
            # Build the input
            $out[] = '<input type="radio" '.$this->createAttrElem($radio).' />';
            # I would check to see if the label is set (you never know)
            if(!empty($radio['label']))
                $out[] = '<label for="'.$radio['id'].'">'.$radio['label'].'</label>';
        }
        # Send back the string
        return implode(PHP_EOL, $out);
    }

    protected function createAttrElem($radio) 
    {
        # See if all these attributes are set first
        if(!empty($radio['id']))
            $attr[] = 'id="'.$radio['id'].'"';
        if(!empty($radio['name']))
            $attr[] = 'name="'.$radio['name'].'"';
        if(!empty($radio['checked']))
            $attr[] = 'checked';
        # Return a string
        return (isset($attr))? implode(' ', $attr) : '';
    }
    /**
     *    @description    I might maybe make this method just run the render method.
     *                    Saves on having to write it out.
     */
    public  function __toString()
    {
        return $this->render();
    }
}

Класс формы может выглядеть примерно так:

class Form
{
    protected   $layout,
                $type;
    /**
     *    @description    I would allow the form class to be flexible but set default to "form"
     */
    public  function    __construct($type = 'form')
    {
        $this->type     = $type;
    }
    /**
     *    @description    Create the open tag
     */
    public function open(array $attr)
    {
        $open[] = '<'.$this->type;
        foreach($attr as $key => $value) {
            $open[] = $key.'="'.$value.'"';
        }
        $this->layout[] = implode(' ', $open).'>';
        return $this;
    }
    /**
     *    @description    Here you would add the children of the parent element
     */
    public function addChild($Object)
    {
        $this->layout[] = $Object->render();
        return $this;
    }
    /**
     *    @description    Close the element
     */
    public function close()
    {
        $this->layout[] = '</'.$this->type.'>';
        return $this;
    }
    /**
     *    @description    Create a string of the layout
     */
    public function render()
    {
        return implode(PHP_EOL, $this->layout);
    }
    /**
     *    @description    Shortcut the render process
     **/
    public  function __toString()
    {
        return $this->render();
    }
}

Затем использовать все это:

$formConf = [
    'kraken' => [
        'type' => 'radio',
        'id' => 'kraken',
        'name' => 'monster',
        'label' => 'Kraken',
        'radio' => 'checked'
    ],

    'sasquatch' => [
        'type' => 'radio',
        'id' => 'sasquatch',
        'name' => 'monster',
        'label' => 'Sasquatch',
        'radio' => ''
    ],

    'mothman' => [
        'type' => 'radio',
        'id' => 'mothman',
        'name' => 'monster',
        'label' => 'Mothman',
        'radio' => ''
    ]
];

$Fieldset   =   new Form('fieldset');

echo $Fieldset->open(['name' => 'test'])
    ->addChild(new Radio($formConf))
    ->close();

Это приведет к выводу:

<fieldset name="test">
<input type="radio" id="kraken" name="monster" />
<label for="kraken">Kraken</label>
<input type="radio" id="sasquatch" name="monster" />
<label for="sasquatch">Sasquatch</label>
<input type="radio" id="mothman" name="monster" />
<label for="mothman">Mothman</label>
</fieldset>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...