diff --git a/.gitignore b/.gitignore index 302e2f7..629ebde 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /vendor /composer.lock /tests/output +/.idea diff --git a/readme.md b/readme.md index 20ea1c8..4610c01 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ In PHP this addon works with DateTime objects, in the browser it uses jqueryUI c [![License](https://poser.pugx.org/voda/date-input/license)](https://packagist.org/packages/voda/date-input) -JS dependencies +JS dependencies (recomended) --------------- * [jQuery](http://jquery.com/) and [jQueryUI](http://jqueryui.com/) * [Timepicker addon](http://trentrichardson.com/examples/timepicker/) version 1.1.0 or newer @@ -30,11 +30,28 @@ insert required javascript and style files into your layout (order of scripts is ``` -register the addon in your bootstrap.php: -``` + +### Registering + +#### Register the addon in your bootstrap.php + +```php Vodacek\Forms\Controls\DateInput::register(); ``` + +#### Or use DI extension + +config.neon: + +```neon +extensions: + dateInput: Vodacek\Forms\Controls\Extension +``` + +### If you want use jQuery calendar (not necessary) + initialize the calendar using javascript: + ```js $(document).ready(function() { $('input[data-dateinput-type]').dateinput({ @@ -71,4 +88,8 @@ $form->addDate('datetimeLocal', 'Local datetime', DateInput::TYPE_DATETIME_LOCAL ->setRequired() ->setDefaultValue(new DateTimeImmutable()) ->addRule(Form::RANGE, null, array(new DateTimeImmutable('-2 years'), new DateTimeImmutable('+2 years'))); + +$form->addDate('date', 'Date', DateInput::TYPE_DATE); + +$form->addDate('time', 'Time', DateInput::TYPE_TIME); ``` diff --git a/src/DateInput.php b/src/DateInput.php index 2a27070..94bcfba 100644 --- a/src/DateInput.php +++ b/src/DateInput.php @@ -31,9 +31,9 @@ use DateTimeInterface; use Nette\Forms\Container; +use Nette\Forms\Control; use Nette\Forms\Controls\BaseControl; use Nette\Forms\Form; -use Nette\Forms\IControl; use Nette\Forms\Validator; /** @@ -44,15 +44,18 @@ class DateInput extends BaseControl { public const - TYPE_DATETIME_LOCAL = 'datetime-local', - TYPE_DATE = 'date', - TYPE_MONTH = 'month', - TYPE_TIME = 'time', - TYPE_WEEK = 'week'; + TYPE_DATETIME_LOCAL = 'datetime-local', + TYPE_DATE = 'date', + TYPE_MONTH = 'month', + TYPE_TIME = 'time', + TYPE_WEEK = 'week'; /** @var string */ protected $type; + /** @var bool */ + private $nullable; + /** @var array */ protected $range = ['min' => null, 'max' => null]; @@ -64,7 +67,7 @@ class DateInput extends BaseControl { public static $defaultValidMessage = 'Please enter a valid date.'; - private static $formats = [ + public static $formats = [ self::TYPE_DATETIME_LOCAL => 'Y-m-d\TH:i:s', self::TYPE_DATE => 'Y-m-d', self::TYPE_MONTH => 'Y-m', @@ -109,6 +112,11 @@ public function __construct(string $label = null, string $type = self::TYPE_DATE } } + /** + * Sets control's value. + * @return static + * @internal + */ public function setValue($value = null) { if ($value === null || $value instanceof DateTimeInterface) { $this->value = $value; @@ -136,6 +144,26 @@ public function setValue($value = null) { return $this; } + /** + * Returns control's value. + * @return mixed + */ + public function getValue() + { + $value = parent::getValue(); + return $this->nullable && $value === '' ? null : $value; + } + + /** + * Sets whether getValue() returns null instead of empty string. + * @return static + */ + public function setNullable(bool $value = true) + { + $this->nullable = $value; + return $this; + } + public function getControl() { $control = parent::getControl(); $format = self::$formats[$this->type]; @@ -165,14 +193,14 @@ public function addRule($operation, $message = null, $arg = null) { return parent::addRule($operation, $message, $arg); } - public static function validateFilled(IControl $control): bool { + public static function validateFilled(Control $control): bool { if (!$control instanceof self) { throw new \InvalidArgumentException("Cant't validate control '".\get_class($control)."'."); } return ($control->value !== null || $control->submittedValue !== null); } - private static function validateValid(IControl $control): bool { + private static function validateValid(Control $control): bool { if (!$control instanceof self) { throw new \InvalidArgumentException("Cant't validate control '".\get_class($control)."'."); } @@ -201,6 +229,10 @@ private function parseValue(string $value): ?DateTimeInterface { } } else { $date = $this->createFromFormat('!'.self::$formats[$this->type], $value); + //try find in format without seconds + if(!$date && $this->type == self::TYPE_DATETIME_LOCAL) { + $date = $this->createFromFormat('!Y-m-d\TH:i', $value); + } } return $date; } diff --git a/src/Extension.php b/src/Extension.php new file mode 100755 index 0000000..5a03b90 --- /dev/null +++ b/src/Extension.php @@ -0,0 +1,23 @@ +methods['initialize']; + /** @see DateInput::register() */ + $init->addBody('Vodacek\Forms\Controls\DateInput::register();'); + } + +} diff --git a/tests/DateInput.validation.phpt b/tests/DateInput.validation.phpt index 487b605..e134051 100644 --- a/tests/DateInput.validation.phpt +++ b/tests/DateInput.validation.phpt @@ -34,6 +34,28 @@ test(static function() { // no value and valid value for required input Assert::false($control->hasErrors()); }); +test(static function() { // value and from browser come different format + $form = new Form(); + $control = new DateInput('date', DateInput::TYPE_DATETIME_LOCAL); + $form->addComponent($control, 'date'); + $control->setRequired(); + + $control->validate(); + Assert::true($control->hasErrors()); + + $control->setValue('2022-04-01T15:15:15'); + $control->validate(); + Assert::false($control->hasErrors()); + + $control->setValue('2022-04-01T15:15:00'); + $control->validate(); + Assert::false($control->hasErrors()); + + $control->setValue('2022-04-01T15:15'); + $control->validate(); + Assert::false($control->hasErrors()); +}); + test(static function() { // invalid value $form = new Form(); $control = new DateInput('date', DateInput::TYPE_DATETIME_LOCAL);