Skip to content

Commit

Permalink
Add docs for Hint widget (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
terabytesoftw committed Nov 9, 2021
1 parent e416ac5 commit a7a28e9
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 26 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -42,6 +42,7 @@ The following documentation describes how to use widgets with PHP:
- [Error](docs/error.md)
- [ErrorSummary](docs/error-summary.md)
- [File](docs/file.md)
- [Hint](docs/hint.md)
- [Number](docs/number.md)
- [Password](docs/password.md)
- [Radio](docs/radio.md)
Expand Down
121 changes: 121 additions & 0 deletions docs/hint.md
@@ -0,0 +1,121 @@
# Hint widget

Displays hint for a field form.

## Usage

```php
<?php

declare(strict_types=1);

namespace App\Form;

use Yiisoft\Form\FormModel;

final class TestForm extends FormModel
{
private string $name = '';

public function getAttributeHints(): array
{
return [
'name' => 'Write your first name.',
];
}
}
```

Widget view:

```php
<?php

declare(strict_types=1);

use Yiisoft\Form\FormModelInterface;
use Yiisoft\Form\Widget\Field;
use Yiisoft\Form\Widget\Form;
use Yiisoft\Form\Widget\Hint;
use Yiisoft\Form\Widget\Text;

/**
* @var FormModelInterface $data
* @var object $csrf
*/
?>

<?= Form::widget()->action('widgets')->csrf($csrf)->begin() ?>
<?= Text::widget()->config($formModel, 'name') ?>
<?= Hint::widget()->config($formModel, 'name') ?>
<hr class="mt-3">
<?= Field::widget()->submitButton(['class' => 'button is-block is-info is-fullwidth', 'value' => 'Save']) ?>
<?= Form::end() ?>
```

That would generate the following code:

```html
<form action="widgets" method="POST" _csrf="BJKr0W43OfWETd0B8fZbrZFOKGzxkdoOZRRcuh4B1Gk3pdK_C2N6xfMbhXiQrjr153kZFrLLtXojcw6OV0CeAg==">
<input type="hidden" name="_csrf" value="BJKr0W43OfWETd0B8fZbrZFOKGzxkdoOZRRcuh4B1Gk3pdK_C2N6xfMbhXiQrjr153kZFrLLtXojcw6OV0CeAg==">
<input type="text" id="testform-name" name="TestForm[name]">
<div>Write your first name.</div>
<hr class="mt-3">
<div>
<input type="submit" id="submit-74174218703001" class="button is-block is-info is-fullwidth" name="submit-74174218703001" value="Save">
</div>
</form>
```

### Custom hint text

You can use custom hint text when calling the widget:

```php
<?php

declare(strict_types=1);

use Yiisoft\Form\FormModelInterface;
use Yiisoft\Form\Widget\Field;
use Yiisoft\Form\Widget\Form;
use Yiisoft\Form\Widget\Hint;
use Yiisoft\Form\Widget\Text;

/**
* @var FormModelInterface $data
* @var object $csrf
*/
?>

<?= Form::widget()->action('widgets')->csrf($csrf)->begin() ?>
<?= Text::widget()->config($formModel, 'name') ?>
<?= Hint::widget()->config($formModel, 'name')->hint('Custom hint text.') ?>
<hr class="mt-3">
<?= Field::widget()->submitButton(['class' => 'button is-block is-info is-fullwidth', 'value' => 'Save']) ?>
<?= Form::end() ?>
```

That would generate the following code:

```html
<form action="widgets" method="POST" _csrf="BJKr0W43OfWETd0B8fZbrZFOKGzxkdoOZRRcuh4B1Gk3pdK_C2N6xfMbhXiQrjr153kZFrLLtXojcw6OV0CeAg==">
<input type="hidden" name="_csrf" value="BJKr0W43OfWETd0B8fZbrZFOKGzxkdoOZRRcuh4B1Gk3pdK_C2N6xfMbhXiQrjr153kZFrLLtXojcw6OV0CeAg==">
<input type="text" id="testform-name" name="TestForm[name]">
<div>Write your first name.</div>
<hr class="mt-3">
<div>
<input type="submit" id="submit-74174218703001" class="button is-block is-info is-fullwidth" name="submit-74174218703001" value="Save">
</div>
</form>
```

### `Hint` methods:

Method | Description | Default
-------|-------------|---------
`config(FormModelInterface $formModel, string $attribute, array $attributes = [])` | Configures the widget. |
`encode(bool $value)` | Whether to encode the error message. | `true`
`message(string $value)` | Error message to display. | `''`
`messageCallback(array $value)` | Callback that will be called to obtain an error message. | `[]`
`tag(string $value)` | Tag to use to display the error. | `'div'`
17 changes: 15 additions & 2 deletions src/Widget/Field.php
Expand Up @@ -393,22 +393,35 @@ public function hidden(array $attributes = []): self
* - `hint`: string, the content of the hint tag. Note that it will NOT be HTML-encoded. If no set, the hint will be
* generated via {@see \Yiisoft\Form\FormModel::getAttributeHint()}. if `null` it will not be rendered.
* - `tag`: string, the tag name of the hint tag. if not set, `div` will be used. if `null` no tag will be used.
* @param string|null $hint The hint text. If value is an empty string, the hint will be generated via
* {@see \Yiisoft\Form\FormModel::getAttributeHint()}, if value is `null`, the hint will not be rendered.
* @param bool $encode Whether content should be HTML-encoded.
*
* @return static
*/
public function hint(array $attributes = []): self
public function hint(array $attributes = [], ?string $hint = '', bool $encode = true): self
{
$new = clone $this;
$hintWidget = Hint::widget();

if ($new->ariaDescribedBy === true) {
$attributes['id'] = $new->getId();
}

if (isset($attributes['tag']) && is_string($attributes['tag'])) {
$hintWidget = $hintWidget->tag($attributes['tag']);
unset($attributes['tag']);
}

if ($new->hintClass !== '') {
Html::addCssClass($attributes, $new->hintClass);
}

$new->parts['{hint}'] = Hint::widget()->config($new->getFormModel(), $new->attribute, $attributes)->render();
$new->parts['{hint}'] = $hintWidget
->config($new->getFormModel(), $new->attribute, $attributes)
->hint($hint)
->encode($encode)
->render();

return $new;
}
Expand Down
102 changes: 84 additions & 18 deletions src/Widget/Hint.php
Expand Up @@ -4,18 +4,87 @@

namespace Yiisoft\Form\Widget;

use Yiisoft\Arrays\ArrayHelper;
use InvalidArgumentException;
use Yiisoft\Form\FormModelInterface;
use Yiisoft\Form\Helper\HtmlForm;
use Yiisoft\Form\Widget\Attribute\ModelAttributes;
use Yiisoft\Html\Tag\CustomTag;
use Yiisoft\Widget\Widget;

/**
* The widget for hint form.
*
* @psalm-suppress MissingConstructor
*/
final class Hint extends Widget
{
use ModelAttributes;
private array $attributes = [];
private string $attribute = '';
private bool $encode = true;
private FormModelInterface $formModel;
private ?string $hint = '';
private string $tag = 'div';

/**
* Specify a form, its attribute and a list HTML attributes for the hint generated.
*
* @param FormModelInterface $formModel Form instance.
* @param string $attribute Form model's property name this widget is rendered for.
* @param array $attributes HTML attributes for the widget container tag.
*
* @return static
*
* {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
*/
public function config(FormModelInterface $formModel, string $attribute, array $attributes = []): self
{
$new = clone $this;
$new->formModel = $formModel;
$new->attribute = $attribute;
$new->attributes = $attributes;
return $new;
}

/**
* Whether content should be HTML-encoded.
*
* @param bool $value
*
* @return static
*/
public function encode(bool $value): self
{
$new = clone $this;
$new->encode = $value;
return $new;
}

/**
* Set hint text.
*
* @param string|null $value
*
* @return static
*/
public function hint(?string $value): self
{
$new = clone $this;
$new->hint = $value;
return $new;
}

/**
* Set the container tag name for the hint.
*
* @param string $value Container tag name. Set to empty value to render error messages without container tag.
*
* @return static
*/
public function tag(string $value): self
{
$new = clone $this;
$new->tag = $value;
return $new;
}

/**
* Generates a hint tag for the given form attribute.
Expand All @@ -26,23 +95,20 @@ protected function run(): string
{
$new = clone $this;

/** @var bool */
$encode = $new->attributes['encode'] ?? false;

/** @var bool|string */
$hint = ArrayHelper::remove(
$new->attributes,
'hint',
HtmlForm::getAttributeHint($new->getFormModel(), $new->attribute),
);

/** @psalm-var non-empty-string */
$tag = $new->attributes['tag'] ?? 'div';
if ($new->hint !== null && $new->hint === '') {
$new->hint = HtmlForm::getAttributeHint($new->formModel, $new->attribute);
}

unset($new->attributes['hint'], $new->attributes['tag']);
if ($new->tag === '') {
throw new InvalidArgumentException('Tag name cannot be empty.');
}

return (!is_bool($hint) && $hint !== '')
? CustomTag::name($tag)->attributes($new->attributes)->content($hint)->encode($encode)->render()
return (!empty($new->hint))
? CustomTag::name($new->tag)
->attributes($new->attributes)
->content($new->hint)
->encode($new->encode)
->render()
: '';
}
}
39 changes: 36 additions & 3 deletions tests/Widget/FieldHintTest.php
Expand Up @@ -27,11 +27,29 @@ public function testAnyHint(): void
HTML;
$this->assertEqualsWithoutLE(
$expected,
Field::widget()->config($this->formModel, 'string')->hint(['hint' => false])->render(),
Field::widget()->config($this->formModel, 'string')->hint([], null)->render(),
);
}

public function testHintCustom(): void
public function testEncodeFalse(): void
{
$expected = <<<'HTML'
<div>
<label for="typeform-string">String</label>
<input type="text" id="typeform-string" name="TypeForm[string]" placeholder="Typed your text string.">
<div>Write&nbsp;your&nbsp;text.</div>
</div>
HTML;
$this->assertEqualsWithoutLE(
$expected,
Field::widget()
->config($this->formModel, 'string')
->hint([], 'Write&nbsp;your&nbsp;text.', false)
->render(),
);
}

public function testHintCustomText(): void
{
$expected = <<<'HTML'
<div>
Expand All @@ -42,7 +60,7 @@ public function testHintCustom(): void
HTML;
$html = Field::widget()
->config($this->formModel, 'string')
->hint(['class' => 'test-class', 'hint' => 'Custom hint text.'])
->hint(['class' => 'test-class'], 'Custom hint text.')
->render();
$this->assertEqualsWithoutLE($expected, $html);
}
Expand All @@ -62,6 +80,21 @@ public function testRender(): void
);
}

public function testTag(): void
{
$expected = <<<'HTML'
<div>
<label for="typeform-string">String</label>
<input type="text" id="typeform-string" name="TypeForm[string]" placeholder="Typed your text string.">
<span>Write your text string.</span>
</div>
HTML;
$this->assertEqualsWithoutLE(
$expected,
Field::widget()->config($this->formModel, 'string')->hint(['tag' => 'span'])->render(),
);
}

protected function setUp(): void
{
parent::setUp();
Expand Down
8 changes: 5 additions & 3 deletions tests/Widget/HintTest.php
Expand Up @@ -21,14 +21,16 @@ public function testContent(): void
{
$this->assertSame(
'<div>Write your text.</div>',
Hint::widget()->config($this->formModel, 'string', ['hint' => 'Write your text.'])->render(),
Hint::widget()->config($this->formModel, 'string')->hint('Write your text.')->render(),
);
}

public function testEncodeFalse(): void
{
$html = Hint::widget()
->config($this->formModel, 'string', ['hint' => 'Write&nbsp;your&nbsp;text.', 'encode' => false])
->config($this->formModel, 'string')
->encode(false)
->hint('Write&nbsp;your&nbsp;text.')
->render();
$this->assertSame('<div>Write&nbsp;your&nbsp;text.</div>', $html);
}
Expand All @@ -45,7 +47,7 @@ public function testTag(): void
{
$this->assertSame(
'<span>Write your text string.</span>',
Hint::widget()->config($this->formModel, 'string', ['tag' => 'span'])->render(),
Hint::widget()->config($this->formModel, 'string')->tag('span')->render(),
);
}

Expand Down

0 comments on commit a7a28e9

Please sign in to comment.