Skip to content

Commit

Permalink
added DateTimeControl & DateControl
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Feb 10, 2019
1 parent aee4b5e commit 44fa26a
Show file tree
Hide file tree
Showing 9 changed files with 441 additions and 2 deletions.
10 changes: 10 additions & 0 deletions examples/datetime/DatetimePresenter.latte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<title>Datetime demo</title>
</head>
<body>
{control form}
</body>
</html>
35 changes: 35 additions & 0 deletions examples/datetime/DatetimePresenter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php declare(strict_types = 1);

namespace NextrasDemos\FormsComponents\Datetime;

use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
use Nextras\FormComponents\Controls\DateControl;
use Nextras\FormComponents\Controls\DateTimeControl;


class DatetimePresenter extends Presenter
{
public function actionDefault()
{
}


public function createComponentForm()
{
$form = new Form();
$form['date'] = new DateControl('Born');
$form['registered'] = new DateTimeControl('Registered');
$form->addSubmit('save', 'Send');
$form->onSuccess[] = function ($form, $values) {
dump($values);
};
return $form;
}


public function formatTemplateFiles(): array
{
return [__DIR__ . '/DatetimePresenter.latte'];
}
}
7 changes: 7 additions & 0 deletions examples/datetime/config.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
application:
scanDirs: false
mapping:
*: NextrasDemos\FormsComponents\Datetime\*Module\*Presenter

services:
routing.router: Nette\Application\Routers\SimpleRouter('Datetime:default')
19 changes: 19 additions & 0 deletions examples/datetime/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types = 1);

namespace NextrasDemos\FormsComponents\Datetime;

use Nette\Application\Application;
use Nette\Configurator;

require_once __DIR__ . '/../../vendor/autoload.php';


$configurator = new Configurator;
$configurator->enableDebugger(__DIR__ . '/log');
$configurator->setTempDirectory(__DIR__ . '/temp');
$configurator->createRobotLoader()->addDirectory(__DIR__)->register();
$configurator->addConfig(__DIR__ . '/config.neon');

$container = $configurator->createContainer();
$app = $container->getByType(Application::class);
$app->run();
4 changes: 2 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Architecture components provide Nette Forms' BaseControl in two flavors:

UI components:
- *AutocompleteControl* - text input with support for autocomplete signal handling;
- *DatePicker* - date picker - text input returning `DateTimeImmutable` instance;
- *DateTimePicker* - date picker - text input returning `DateTimeImmutable` instance;
- *DateControl* - date picker - text input returning `DateTimeImmutable` instance;
- *DateTimeControl* - date tiime picker - text input returning `DateTimeImmutable` instance;

### Installation

Expand Down
67 changes: 67 additions & 0 deletions src/Controls/DateControl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras community extensions of Nette Framework
*
* @license MIT
* @link https://github.com/nextras/form-components
*/

namespace Nextras\FormComponents\Controls;

use DateTimeImmutable;


class DateControl extends DateTimeControlPrototype
{
/** @link http://dev.w3.org/html5/spec/common-microsyntaxes.html#valid-date-string */
protected const W3C_DATE_FORMAT = 'Y-m-d';

/** @var string */
protected $htmlFormat = self::W3C_DATE_FORMAT;

/** @var string */
protected $htmlType = 'date';


protected function getDefaultParser()
{
return function($value) {
try {
return new DateTimeImmutable($value);
} catch (\Exception $e) {
// fallback to custm parsing
}

if (!preg_match('#^(?P<dd>\d{1,2})[. -]\s*(?P<mm>\d{1,2})([. -]\s*(?P<yyyy>\d{4})?)?$#', $value, $matches)) {
return null;
}

$dd = $matches['dd'];
$mm = $matches['mm'];
$yyyy = $matches['yyyy'] ?? date('Y');

if (!checkdate($mm, $dd, $yyyy)) {
return null;
}

return (new DateTimeImmutable())
->setDate($yyyy, $mm, $dd)
->setTime(0, 0, 0);
};
}


/**
* @return DateTimeImmutable|null
*/
public function getValue()
{
$val = parent::getValue();
// set the midnight so the limit dates (min & max) pass the :RANGE validation rule
if ($val !== null) {
return $val->setTime(0, 0, 0);
}
return $val;
}
}
61 changes: 61 additions & 0 deletions src/Controls/DateTimeControl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras community extensions of Nette Framework
*
* @license MIT
* @link https://github.com/nextras/form-components
*/

namespace Nextras\FormComponents\Controls;

use DateTimeImmutable;


class DateTimeControl extends DateTimeControlPrototype
{
/** @link http://dev.w3.org/html5/spec/common-microsyntaxes.html#parse-a-local-date-and-time-string */
protected const W3C_DATETIME_FORMAT = 'Y-m-d\TH:i:s';

/** @var string */
protected $htmlFormat = self::W3C_DATETIME_FORMAT;

/** @var string */
protected $htmlType = 'datetime-local';


protected function getDefaultParser()
{
return function($value) {
try {
return new DateTimeImmutable($value);
} catch (\Exception $e) {
// fallback to custm parsing
}

if (!preg_match('#^(?P<dd>\d{1,2})[. -]\s*(?P<mm>\d{1,2})(?:[. -]\s*(?P<yyyy>\d{4})?)?(?:\s*[ @-]\s*(?P<hh>\d{1,2})[:.](?P<ii>\d{1,2})(?:[:.](?P<ss>\d{1,2}))?)?$#', $value, $matches)) {
return null;
}

$dd = $matches['dd'];
$mm = $matches['mm'];
$yyyy = $matches['yyyy'] ?? date('Y');

if (!checkdate($mm, $dd, $yyyy)) {
return null;
}

$hh = $matches['hh'] ?? 0;
$ii = $matches['ii'] ?? 0;
$ss = $matches['ss'] ?? 0;

if (!($hh >= 0 && $hh < 24 && $ii >= 0 && $ii <= 59 && $ss >= 0 && $ss <= 59)) {
return null;
}

return (new DateTimeImmutable())
->setDate($yyyy, $mm, $dd)
->setTime($hh, $ii, $ss);
};
}
}
146 changes: 146 additions & 0 deletions src/Controls/DateTimeControlPrototype.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras community extensions of Nette Framework
*
* @license MIT
* @link https://github.com/nextras/form-components
*/

namespace Nextras\FormComponents\Controls;

use DateTime;
use DateTimeImmutable;
use DateTimeInterface;
use Nette;
use Nette\Forms\Controls\TextBase;
use Nette\Forms\Form;
use Nette\Forms\Rules;
use Nette\Utils\Html;


abstract class DateTimeControlPrototype extends TextBase
{
/** @var string */
protected $htmlFormat;

/** @var string */
protected $htmlType;

/** @var callable[] */
protected $parsers = [];


public function getControl(): Html
{
$control = parent::getControl();
$control->type = $this->htmlType;
$control->addClass($this->htmlType);

list($min, $max) = $this->extractRangeRule($this->getRules());
if ($min instanceof DateTimeInterface) {
$control->min = $min->format($this->htmlFormat);
}
if ($max instanceof DateTimeInterface) {
$control->max = $max->format($this->htmlFormat);
}
$value = $this->getValue();
if ($value instanceof DateTimeInterface) {
$control->value = $value->format($this->htmlFormat);
}

return $control;
}


public function setValue($value)
{
return parent::setValue(
$value instanceof DateTimeInterface
? $value->format($this->htmlFormat)
: $value
);
}


/**
* @return DateTimeImmutable|null
*/
public function getValue()
{
if ($this->value instanceof DateTimeImmutable) {
return $this->value;

} elseif ($this->value instanceof DateTime) {
return DateTimeImmutable::createFromMutable($this->value);

} elseif (empty($this->value)) {
return null;

} elseif (is_string($this->value)) {
$parsers = $this->parsers;
$parsers[] = $this->getDefaultParser();

foreach ($parsers as $parser) {
$value = call_user_func($parser, $this->value);
if ($value instanceof DateTimeImmutable) {
return $value;
} elseif ($value instanceof DateTime) {
return DateTimeImmutable::createFromMutable($value);
}
}

// fall-through
}

return null;
}


public function addParser(callable $parser)
{
$this->parsers[] = $parser;
return $this;
}


abstract protected function getDefaultParser();


/**
* Finds minimum and maximum allowed dates.
*
* @return array 0 => DateTime|null $minDate, 1 => DateTime|null $maxDate
*/
protected function extractRangeRule(Rules $rules)
{
$controlMin = $controlMax = null;
/** @var Nette\Forms\Rule $rule */
foreach ($rules as $rule) {
/** @var Rules|null $branch */
$branch = $rule->branch;
if ($branch === null) {
if ($rule->validator === Form::RANGE && !$rule->isNegative) {
$ruleMinMax = $rule->arg;
}

} else {
if ($rule->validator === Form::FILLED && !$rule->isNegative && $rule->control === $this) {
$ruleMinMax = $this->extractRangeRule($branch);
}
}

if (isset($ruleMinMax)) {
list($ruleMin, $ruleMax) = $ruleMinMax;
if ($ruleMin !== null && ($controlMin === null || $ruleMin > $controlMin)) {
$controlMin = $ruleMin;
}
if ($ruleMax !== null && ($controlMax === null || $ruleMax < $controlMax)) {
$controlMax = $ruleMax;
}
$ruleMinMax = null;
}
}
return [$controlMin, $controlMax];
}
}
Loading

0 comments on commit 44fa26a

Please sign in to comment.