1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\Form\View\Helper;
11
12use Zend\Form\ElementInterface;
13use Zend\Form\Exception;
14use Zend\Form\LabelAwareInterface;
15
16class FormButton extends FormInput
17{
18    /**
19     * Attributes valid for the button tag
20     *
21     * @var array
22     */
23    protected $validTagAttributes = array(
24        'name'           => true,
25        'autofocus'      => true,
26        'disabled'       => true,
27        'form'           => true,
28        'formaction'     => true,
29        'formenctype'    => true,
30        'formmethod'     => true,
31        'formnovalidate' => true,
32        'formtarget'     => true,
33        'type'           => true,
34        'value'          => true,
35    );
36
37    /**
38     * Valid values for the button type
39     *
40     * @var array
41     */
42    protected $validTypes = array(
43        'button'         => true,
44        'reset'          => true,
45        'submit'         => true,
46    );
47
48    /**
49     * Invoke helper as functor
50     *
51     * Proxies to {@link render()}.
52     *
53     * @param  ElementInterface|null $element
54     * @param  null|string           $buttonContent
55     * @return string|FormButton
56     */
57    public function __invoke(ElementInterface $element = null, $buttonContent = null)
58    {
59        if (!$element) {
60            return $this;
61        }
62
63        return $this->render($element, $buttonContent);
64    }
65
66    /**
67     * Render a form <button> element from the provided $element,
68     * using content from $buttonContent or the element's "label" attribute
69     *
70     * @param  ElementInterface $element
71     * @param  null|string $buttonContent
72     * @throws Exception\DomainException
73     * @return string
74     */
75    public function render(ElementInterface $element, $buttonContent = null)
76    {
77        $openTag = $this->openTag($element);
78
79        if (null === $buttonContent) {
80            $buttonContent = $element->getLabel();
81            if (null === $buttonContent) {
82                throw new Exception\DomainException(
83                    sprintf(
84                        '%s expects either button content as the second argument, ' .
85                        'or that the element provided has a label value; neither found',
86                        __METHOD__
87                    )
88                );
89            }
90        }
91
92        if (null !== ($translator = $this->getTranslator())) {
93            $buttonContent = $translator->translate(
94                $buttonContent, $this->getTranslatorTextDomain()
95            );
96        }
97
98
99        if (! $element instanceof LabelAwareInterface || ! $element->getLabelOption('disable_html_escape')) {
100            $escapeHtmlHelper = $this->getEscapeHtmlHelper();
101            $buttonContent = $escapeHtmlHelper($buttonContent);
102        }
103
104        return $openTag . $buttonContent . $this->closeTag();
105    }
106
107    /**
108     * Generate an opening button tag
109     *
110     * @param  null|array|ElementInterface $attributesOrElement
111     * @throws Exception\InvalidArgumentException
112     * @throws Exception\DomainException
113     * @return string
114     */
115    public function openTag($attributesOrElement = null)
116    {
117        if (null === $attributesOrElement) {
118            return '<button>';
119        }
120
121        if (is_array($attributesOrElement)) {
122            $attributes = $this->createAttributesString($attributesOrElement);
123            return sprintf('<button %s>', $attributes);
124        }
125
126        if (!$attributesOrElement instanceof ElementInterface) {
127            throw new Exception\InvalidArgumentException(sprintf(
128                '%s expects an array or Zend\Form\ElementInterface instance; received "%s"',
129                __METHOD__,
130                (is_object($attributesOrElement) ? get_class($attributesOrElement) : gettype($attributesOrElement))
131            ));
132        }
133
134        $element = $attributesOrElement;
135        $name    = $element->getName();
136        if (empty($name) && $name !== 0) {
137            throw new Exception\DomainException(sprintf(
138                '%s requires that the element has an assigned name; none discovered',
139                __METHOD__
140            ));
141        }
142
143        $attributes          = $element->getAttributes();
144        $attributes['name']  = $name;
145        $attributes['type']  = $this->getType($element);
146        $attributes['value'] = $element->getValue();
147
148        return sprintf(
149            '<button %s>',
150            $this->createAttributesString($attributes)
151        );
152    }
153
154    /**
155     * Return a closing button tag
156     *
157     * @return string
158     */
159    public function closeTag()
160    {
161        return '</button>';
162    }
163
164    /**
165     * Determine button type to use
166     *
167     * @param  ElementInterface $element
168     * @return string
169     */
170    protected function getType(ElementInterface $element)
171    {
172        $type = $element->getAttribute('type');
173        if (empty($type)) {
174            return 'submit';
175        }
176
177        $type = strtolower($type);
178        if (!isset($this->validTypes[$type])) {
179            return 'submit';
180        }
181
182        return $type;
183    }
184}
185