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\Element; 11 12use DateTime as PhpDateTime; 13use Traversable; 14use Zend\Form\Element; 15use Zend\Form\ElementPrepareAwareInterface; 16use Zend\Form\FormInterface; 17use Zend\InputFilter\InputProviderInterface; 18use Zend\Stdlib\ArrayUtils; 19use Zend\Validator\Regex as RegexValidator; 20use Zend\Validator\ValidatorInterface; 21 22class MonthSelect extends Element implements InputProviderInterface, ElementPrepareAwareInterface 23{ 24 /** 25 * Select form element that contains values for month 26 * 27 * @var Select 28 */ 29 protected $monthElement; 30 31 /** 32 * Select form element that contains values for year 33 * 34 * @var Select 35 */ 36 protected $yearElement; 37 38 /** 39 * Min year to use for the select (default: current year - 100) 40 * 41 * @var int 42 */ 43 protected $minYear; 44 45 /** 46 * Max year to use for the select (default: current year) 47 * 48 * @var int 49 */ 50 protected $maxYear; 51 52 /** 53 * If set to true, it will generate an empty option for every select (this is mainly needed by most JavaScript 54 * libraries to allow to have a placeholder) 55 * 56 * @var bool 57 */ 58 protected $createEmptyOption = false; 59 60 /** 61 * If set to true, view helpers will render delimiters between <select> elements, according to the 62 * specified locale 63 * 64 * @var bool 65 */ 66 protected $renderDelimiters = true; 67 68 /** 69 * @var ValidatorInterface 70 */ 71 protected $validator; 72 73 /** 74 * Constructor. Add two selects elements 75 * 76 * @param null|int|string $name Optional name for the element 77 * @param array $options Optional options for the element 78 */ 79 public function __construct($name = null, $options = array()) 80 { 81 $this->minYear = date('Y') - 100; 82 $this->maxYear = date('Y'); 83 84 $this->monthElement = new Select('month'); 85 $this->yearElement = new Select('year'); 86 87 parent::__construct($name, $options); 88 } 89 90 /** 91 * Set element options. 92 * 93 * Accepted options for MonthSelect: 94 * 95 * - month_attributes: HTML attributes to be rendered with the month element 96 * - year_attributes: HTML attributes to be rendered with the month element 97 * - min_year: min year to use in the year select 98 * - max_year: max year to use in the year select 99 * 100 * @param array|Traversable $options 101 * @return self 102 */ 103 public function setOptions($options) 104 { 105 parent::setOptions($options); 106 107 if ($options instanceof Traversable) { 108 $options = ArrayUtils::iteratorToArray($options); 109 } 110 111 if (isset($options['month_attributes'])) { 112 $this->setMonthAttributes($options['month_attributes']); 113 } 114 115 if (isset($options['year_attributes'])) { 116 $this->setYearAttributes($options['year_attributes']); 117 } 118 119 if (isset($options['min_year'])) { 120 $this->setMinYear($options['min_year']); 121 } 122 123 if (isset($options['max_year'])) { 124 $this->setMaxYear($options['max_year']); 125 } 126 127 if (isset($options['create_empty_option'])) { 128 $this->setShouldCreateEmptyOption($options['create_empty_option']); 129 } 130 131 if (isset($options['render_delimiters'])) { 132 $this->setShouldRenderDelimiters($options['render_delimiters']); 133 } 134 135 return $this; 136 } 137 138 /** 139 * @return Select 140 */ 141 public function getMonthElement() 142 { 143 return $this->monthElement; 144 } 145 146 /** 147 * @return Select 148 */ 149 public function getYearElement() 150 { 151 return $this->yearElement; 152 } 153 154 /** 155 * Get both the year and month elements 156 * 157 * @return array 158 */ 159 public function getElements() 160 { 161 return array($this->monthElement, $this->yearElement); 162 } 163 164 /** 165 * Set the month attributes 166 * 167 * @param array $monthAttributes 168 * @return self 169 */ 170 public function setMonthAttributes(array $monthAttributes) 171 { 172 $this->monthElement->setAttributes($monthAttributes); 173 return $this; 174 } 175 176 /** 177 * Get the month attributes 178 * 179 * @return array 180 */ 181 public function getMonthAttributes() 182 { 183 return $this->monthElement->getAttributes(); 184 } 185 186 /** 187 * Set the year attributes 188 * 189 * @param array $yearAttributes 190 * @return self 191 */ 192 public function setYearAttributes(array $yearAttributes) 193 { 194 $this->yearElement->setAttributes($yearAttributes); 195 return $this; 196 } 197 198 /** 199 * Get the year attributes 200 * 201 * @return array 202 */ 203 public function getYearAttributes() 204 { 205 return $this->yearElement->getAttributes(); 206 } 207 208 /** 209 * @param int $minYear 210 * @return self 211 */ 212 public function setMinYear($minYear) 213 { 214 $this->minYear = $minYear; 215 return $this; 216 } 217 218 /** 219 * @return int 220 */ 221 public function getMinYear() 222 { 223 return $this->minYear; 224 } 225 226 /** 227 * @param int $maxYear 228 * @return self 229 */ 230 public function setMaxYear($maxYear) 231 { 232 $this->maxYear = $maxYear; 233 return $this; 234 } 235 236 /** 237 * @return int 238 */ 239 public function getMaxYear() 240 { 241 return $this->maxYear; 242 } 243 244 /** 245 * @param bool $createEmptyOption 246 * @return self 247 */ 248 public function setShouldCreateEmptyOption($createEmptyOption) 249 { 250 $this->createEmptyOption = (bool) $createEmptyOption; 251 return $this; 252 } 253 254 /** 255 * @return bool 256 */ 257 public function shouldCreateEmptyOption() 258 { 259 return $this->createEmptyOption; 260 } 261 262 /** 263 * @param bool $renderDelimiters 264 * @return self 265 */ 266 public function setShouldRenderDelimiters($renderDelimiters) 267 { 268 $this->renderDelimiters = (bool) $renderDelimiters; 269 return $this; 270 } 271 272 /** 273 * @return bool 274 */ 275 public function shouldRenderDelimiters() 276 { 277 return $this->renderDelimiters; 278 } 279 280 /** 281 * @param mixed $value 282 * @return self 283 */ 284 public function setValue($value) 285 { 286 if ($value instanceof PhpDateTime) { 287 $value = array( 288 'year' => $value->format('Y'), 289 'month' => $value->format('m') 290 ); 291 } 292 293 $this->yearElement->setValue($value['year']); 294 $this->monthElement->setValue($value['month']); 295 return $this; 296 } 297 298 /** 299 * @return string 300 */ 301 public function getValue() 302 { 303 return sprintf( 304 '%s-%s', 305 $this->getYearElement()->getValue(), 306 $this->getMonthElement()->getValue() 307 ); 308 } 309 310 /** 311 * Prepare the form element (mostly used for rendering purposes) 312 * 313 * @param FormInterface $form 314 * @return void 315 */ 316 public function prepareElement(FormInterface $form) 317 { 318 $name = $this->getName(); 319 $this->monthElement->setName($name . '[month]'); 320 $this->yearElement->setName($name . '[year]'); 321 } 322 323 /** 324 * Get validator 325 * 326 * @return ValidatorInterface 327 */ 328 protected function getValidator() 329 { 330 return new RegexValidator('/^[0-9]{4}\-(0?[1-9]|1[012])$/'); 331 } 332 333 /** 334 * Should return an array specification compatible with 335 * {@link Zend\InputFilter\Factory::createInput()}. 336 * 337 * @return array 338 */ 339 public function getInputSpecification() 340 { 341 return array( 342 'name' => $this->getName(), 343 'required' => false, 344 'filters' => array( 345 array('name' => 'MonthSelect'), 346 ), 347 'validators' => array( 348 $this->getValidator(), 349 ), 350 ); 351 } 352 353 /** 354 * Clone the element (this is needed by Collection element, as it needs different copies of the elements) 355 */ 356 public function __clone() 357 { 358 $this->monthElement = clone $this->monthElement; 359 $this->yearElement = clone $this->yearElement; 360 } 361} 362