initUtils(); $this->availableFields = (int) date('t'); } /** * Set the available fields/days of the month to be rendered * * @param int $fields * * @return $this */ public function setAvailableFields(int $fields): self { $this->availableFields = $fields; return $this; } /** * Set the default field/day to be selected * * @param int $default * * @return $this */ public function setDefault(int $default): self { $this->default = $default; return $this; } /** * Get all the selected weekdays * * @return array */ public function getSelectedDays(): array { $selectedDays = []; foreach (range(1, $this->availableFields) as $day) { if ($this->getValue("day$day", 'n') === 'y') { $selectedDays[] = $day; } } if (empty($selectedDays)) { $selectedDays[] = $this->default; } return $selectedDays; } protected function assemble() { $this->getAttributes()->set('id', $this->protectId('monthly-fields')); $runsOn = $this->getPopulatedValue('runsOn', static::RUNS_EACH); $this->addElement('radio', 'runsOn', [ 'required' => true, 'class' => 'autosubmit', 'value' => $runsOn, 'options' => [static::RUNS_EACH => $this->translate('Each')], ]); $listItems = HtmlElement::create('ul', ['class' => ['schedule-element-fields', 'multiple-fields']]); if ($runsOn === static::RUNS_ONTHE) { $listItems->getAttributes()->add('class', 'disabled'); } foreach (range(1, $this->availableFields) as $day) { $checkbox = $this->createElement('checkbox', "day$day", [ 'class' => ['autosubmit', 'sr-only'], 'value' => $day === $this->default && $runsOn === static::RUNS_EACH ]); $this->registerElement($checkbox); $htmlId = $this->protectId("day$day"); $checkbox->getAttributes()->set('id', $htmlId); $listItem = HtmlElement::create('li'); $listItem->addHtml($checkbox, HtmlElement::create('label', ['for' => $htmlId], $day)); $listItems->addHtml($listItem); } $monthlyWrapper = HtmlElement::create('div', ['class' => 'monthly']); $runsEach = $this->getElement('runsOn'); $runsEach->prependWrapper($monthlyWrapper); $monthlyWrapper->addHtml($runsEach, $listItems); $this->addElement('radio', 'runsOn', [ 'required' => $runsOn !== static::RUNS_EACH, 'class' => 'autosubmit', 'options' => [static::RUNS_ONTHE => $this->translate('On the')], 'validators' => [ new InArrayValidator([ 'strict' => true, 'haystack' => [static::RUNS_EACH, static::RUNS_ONTHE] ]) ] ]); $ordinalWrapper = HtmlElement::create('div', ['class' => 'ordinal']); $runsOnThe = $this->getElement('runsOn'); $runsOnThe->prependWrapper($ordinalWrapper); $ordinalWrapper->addHtml($runsOnThe); $enumerations = $this->createOrdinalElement(); $enumerations->getAttributes()->set('disabled', $runsOn === static::RUNS_EACH); $this->registerElement($enumerations); $selectableDays = $this->createOrdinalSelectableDays(); $selectableDays->getAttributes()->set('disabled', $runsOn === static::RUNS_EACH); $this->registerElement($selectableDays); $ordinalWrapper->addHtml($enumerations, $selectableDays); } protected function registerAttributeCallbacks(Attributes $attributes) { parent::registerAttributeCallbacks($attributes); $attributes ->registerAttributeCallback('default', null, [$this, 'setDefault']) ->registerAttributeCallback('availableFields', null, [$this, 'setAvailableFields']) ->registerAttributeCallback('protector', null, [$this, 'setIdProtector']); } protected function addDefaultValidators(ValidatorChain $chain): void { $chain->add( new CallbackValidator(function ($_, CallbackValidator $validator): bool { if ($this->getValue('runsOn', static::RUNS_EACH) !== static::RUNS_EACH) { return true; } $valid = false; foreach (range(1, $this->availableFields) as $day) { if ($this->getValue("day$day") === 'y') { $valid = true; break; } } if (! $valid) { $validator->addMessage($this->translate('You must select at least one of these days')); } return $valid; }) ); } }