/src/DluTwBootstrap/Form/View/Helper/FormMonthSelectTwb.php

https://bitbucket.org/dominicwatson/dlutwbootstrap-active · PHP · 321 lines · 167 code · 45 blank · 109 comment · 20 complexity · e7fd1464c0a0c13def9271924005ba7e MD5 · raw file

  1. <?php
  2. namespace DluTwBootstrap\Form\View\Helper;
  3. use DateTime;
  4. use IntlDateFormatter;
  5. use Locale;
  6. use Zend\Form\ElementInterface;
  7. use Zend\Form\Element\MonthSelect as MonthSelectElement;
  8. use Zend\Form\Exception;
  9. use Zend\Form\View\Helper\AbstractHelper;
  10. use DluTwBootstrap\Form\FormUtil;
  11. class FormMonthSelectTwb extends AbstractHelper
  12. {
  13. /**
  14. * FormSelect helper
  15. *
  16. * @var FormSelect
  17. */
  18. protected $selectHelper;
  19. /**
  20. * Date formatter to use
  21. *
  22. * @var int
  23. */
  24. protected $dateType;
  25. /**
  26. * Pattern to use for Date rendering
  27. *
  28. * @var string
  29. */
  30. protected $pattern;
  31. /**
  32. * Locale to use
  33. *
  34. * @var string
  35. */
  36. protected $locale;
  37. /**
  38. * General utils
  39. * @var GenUtil
  40. */
  41. protected $genUtil;
  42. /**
  43. * Form utils
  44. * @var \DluTwBootstrap\Form\FormUtil
  45. */
  46. protected $formUtil;
  47. /* **************************** METHODS ****************************** */
  48. /**
  49. * Constructor
  50. * @param \DluTwBootstrap\GenUtil $genUtil
  51. * @param \DluTwBootstrap\Form\FormUtil $formUtil
  52. */
  53. public function __construct(FormUtil $formUtil)
  54. {
  55. $this->formUtil = $formUtil;
  56. }
  57. /**
  58. * Render a month element that is composed of two selects
  59. *
  60. * @param \Zend\Form\ElementInterface $element
  61. * @throws \Zend\Form\Exception\InvalidArgumentException
  62. * @throws \Zend\Form\Exception\DomainException
  63. * @return string
  64. */
  65. public function render(ElementInterface $element, $formType = null, array $displayOptions = array())
  66. {
  67. if (!$element instanceof MonthSelectElement) {
  68. throw new Exception\InvalidArgumentException(sprintf(
  69. '%s requires that the element is of type Zend\Form\Element\MonthSelect',
  70. __METHOD__
  71. ));
  72. }
  73. $name = $element->getName();
  74. if ($name === null || $name === '') {
  75. throw new Exception\DomainException(sprintf(
  76. '%s requires that the element has an assigned name; none discovered',
  77. __METHOD__
  78. ));
  79. }
  80. // Allow passing of options to each of the rendered elements
  81. if (!array_key_exists('day', $displayOptions)) {
  82. $displayOptions['day'] = array();
  83. }
  84. if (!array_key_exists('month', $displayOptions)) {
  85. $displayOptions['month'] = array();
  86. }
  87. if (!array_key_exists('year', $displayOptions)) {
  88. $displayOptions['year'] = array();
  89. }
  90. $selectHelper = $this->getSelectElementHelper();
  91. $pattern = $this->parsePattern($element->shouldRenderDelimiters());
  92. // The pattern always contains "day" part and the first separator, so we have to remove it
  93. unset($pattern['day']);
  94. unset($pattern[0]);
  95. $monthsOptions = $this->getMonthsOptions($pattern['month']);
  96. $yearOptions = $this->getYearsOptions($element->getMinYear(), $element->getMaxYear());
  97. $monthElement = $element->getMonthElement()->setValueOptions($monthsOptions);
  98. $yearElement = $element->getYearElement()->setValueOptions($yearOptions);
  99. if ($element->shouldCreateEmptyOption()) {
  100. $monthElement->setEmptyOption('');
  101. $yearElement->setEmptyOption('');
  102. }
  103. $data = array();
  104. $data[$pattern['month']] = $selectHelper->render($monthElement, $formType, $displayOptions['month']);
  105. $data[$pattern['year']] = $selectHelper->render($yearElement, $formType, $displayOptions['year']);
  106. $markup = '';
  107. foreach ($pattern as $key => $value) {
  108. // Delimiter
  109. if (is_numeric($key)) {
  110. $markup .= $value;
  111. } else {
  112. $markup .= $data[$value];
  113. }
  114. }
  115. return $markup;
  116. }
  117. /**
  118. * Invoke helper as function
  119. *
  120. * Proxies to {@link render()}.
  121. *
  122. * @param \Zend\Form\ElementInterface $element
  123. * @param int $dateType
  124. * @param null|string $locale
  125. * @return FormDateSelect
  126. */
  127. public function __invoke(ElementInterface $element = null, $formType = null,
  128. array $displayOptions = array(),
  129. $dateType = IntlDateFormatter::LONG, $locale = null)
  130. {
  131. if (!$element) {
  132. return $this;
  133. }
  134. $this->setDateType($dateType);
  135. if ($locale !== null) {
  136. $this->setLocale($locale);
  137. }
  138. return $this->render($element, $formType, $displayOptions);
  139. }
  140. /**
  141. * Parse the pattern
  142. *
  143. * @param bool $renderDelimiters
  144. * @return array
  145. */
  146. protected function parsePattern($renderDelimiters = true)
  147. {
  148. $pattern = $this->getPattern();
  149. $pregResult = preg_split("/([ -,.\/]*(?:'[a-zA-Z]+')*[ -,.\/]+)/", $pattern, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  150. $result = array();
  151. foreach ($pregResult as $value) {
  152. if (stripos($value, "'") === false && stripos($value, 'd') !== false) {
  153. $result['day'] = $value;
  154. } elseif (stripos($value, "'") === false && stripos($value, 'm') !== false) {
  155. $result['month'] = $value;
  156. } elseif (stripos($value, "'") === false && stripos($value, 'y') !== false) {
  157. $result['year'] = $value;
  158. } elseif ($renderDelimiters) {
  159. $result[] = str_replace("'", '', $value);
  160. }
  161. }
  162. return $result;
  163. }
  164. /**
  165. * Retrive pattern to use for Date rendering
  166. *
  167. * @return string
  168. */
  169. public function getPattern()
  170. {
  171. if (null === $this->pattern) {
  172. $intl = new IntlDateFormatter($this->getLocale(), $this->dateType, IntlDateFormatter::NONE);
  173. $this->pattern = $intl->getPattern();
  174. }
  175. return $this->pattern;
  176. }
  177. /**
  178. * Set date formatter
  179. *
  180. * @param int $dateType
  181. * @return FormDateSelect
  182. */
  183. public function setDateType($dateType)
  184. {
  185. // The FULL format uses values that are not used
  186. if ($dateType === IntlDateFormatter::FULL) {
  187. $dateType = IntlDateFormatter::LONG;
  188. }
  189. $this->dateType = $dateType;
  190. return $this;
  191. }
  192. /**
  193. * Get date formatter
  194. *
  195. * @return int
  196. */
  197. public function getDateType()
  198. {
  199. return $this->dateType;
  200. }
  201. /**
  202. * Set locale
  203. *
  204. * @param string $locale
  205. * @return FormDateSelect
  206. */
  207. public function setLocale($locale)
  208. {
  209. $this->locale = $locale;
  210. return $this;
  211. }
  212. /**
  213. * Get locale
  214. *
  215. * @return string
  216. */
  217. public function getLocale()
  218. {
  219. if (null === $this->locale) {
  220. $this->locale = Locale::getDefault();
  221. }
  222. return $this->locale;
  223. }
  224. /**
  225. * Create a key => value options for months
  226. *
  227. * @param string $pattern Pattern to use for months
  228. * @return array
  229. */
  230. protected function getMonthsOptions($pattern)
  231. {
  232. $keyFormatter = new IntlDateFormatter($this->getLocale(), null, null, null, null, 'MM');
  233. $valueFormatter = new IntlDateFormatter($this->getLocale(), null, null, null, null, $pattern);
  234. $date = new DateTime('1970-01-01');
  235. $result = array();
  236. for ($month = 1; $month <= 12; $month++) {
  237. $key = $keyFormatter->format($date->getTimestamp());
  238. $value = $valueFormatter->format($date->getTimestamp());
  239. $result[$key] = $value;
  240. $date->modify('+1 month');
  241. }
  242. return $result;
  243. }
  244. /**
  245. * Create a key => value options for years
  246. * NOTE: we don't use a pattern for years, as years written as two digits can lead to hard to
  247. * read date for users, so we only use four digits years
  248. *
  249. * @param int $minYear
  250. * @param int $maxYear
  251. * @return array
  252. */
  253. protected function getYearsOptions($minYear, $maxYear)
  254. {
  255. $result = array();
  256. for ($i = $maxYear; $i >= $minYear; --$i) {
  257. $result[$i] = $i;
  258. }
  259. return $result;
  260. }
  261. /**
  262. * Retrieve the FormSelectTwb helper
  263. *
  264. * @return FormRow
  265. */
  266. protected function getSelectElementHelper()
  267. {
  268. if ($this->selectHelper) {
  269. return $this->selectHelper;
  270. }
  271. if (method_exists($this->view, 'plugin')) {
  272. $this->selectHelper = $this->view->plugin('formselecttwb');
  273. }
  274. return $this->selectHelper;
  275. }
  276. }