Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
- Initial release
- Enh #2: Add helper `Template::class` (@terabytesoftw)
- Bug #3: Fix `README.md` (@terabytesoftw)
- Enh #4: Add helper `HTMLBuilder::class` (@terabytesoftw)
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,52 @@ private array $attributes = ['class' => 'btn'];
$classes = CssClasses::add($this->attributes, ['btn-primary', 'btn-lg'], true);
```

### Create a new `HTML` element

To create a new `HTML` element, you can use the `HTMLBuilder::class` with the `createTag()` method.

Allowed arguments are:

- `tag` (string) - The tag name.
- `content` (string) - The content of the tag.
- `attributes` (array) - The attributes of the tag.

```php
<?php

declare(strict_types=1);

use UIAwesome\Html\Helper\HTMLBuilder;
?>

<?= HTMLBuilder::createTag('div', 'Hello, World!', ['class' => 'container']) ?>
```

### Create a new `HTML` block element

To create a new `HTML` block element, you can use the `HTMLBuilder::class` with the `beginTag()` and `endTag()` methods.

Allowed arguments for `beginTag()` method are:

- `tag` (string) - The tag name.
- `attributes` (array) - The attributes of the tag.

Allowed arguments for `endTag()` method are:

- `tag` (string) - The tag name.

```php
<?php

declare(strict_types=1);

use UIAwesome\Html\Helper\HTMLBuilder;

<?= HTMLBuilder::beginTag('div', ['class' => 'container']) ?>
Hello, World!
<?= HTMLBuilder::endTag('div') ?>
```

### Convert regular expression to pattern

The `Utils::class` helper can be used to normalize a regular expression.
Expand Down
203 changes: 203 additions & 0 deletions src/Base/AbstractHTMLBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
<?php

declare(strict_types=1);

namespace UIAwesome\Html\Helper\Base;

use UIAwesome\Html\Helper\Attributes;

use function in_array;
use function strtolower;

/**
* Provides common functionality for generate HTML code fragments programmatically.
*
* Concrete classes should extend this class to implement specific HTML elements and their generation logic.
*/
abstract class AbstractHTMLBuilder
{
/**
* @psalm-var string[]
*/
private const INLINE_ELEMENTS = [
'a',
'abbr',
'acronym',
'audio',
'b',
'bdi',
'bdo',
'big',
'br',
'button',
'canvas',
'cite',
'code',
'data',
'datalist',
'del',
'dfn',
'em',
'embed',
'i',
'iframe',
'img',
'input',
'ins',
'kbd',
'label',
'map',
'mark',
'meter',
'noscript',
'object',
'option',
'output',
'picture',
'progress',
'q',
'ruby',
's',
'samp',
'script',
'select',
'slot',
'small',
'span',
'strong',
'sub',
'sup',
'svg',
'template',
'textarea',
'time',
'u',
'td',
'th',
'tt',
'var',
'video',
'wbr',
];

/**
* @psalm-var string[]
*/
private const VOID_ELEMENT = [
'area',
'base',
'br',
'col',
'command',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'meta',
'param',
'source',
'track',
'wbr',
];

/**
* This method creates a new HTML begin tag with the specified tag name and attributes.
*
* @param string $tag The tag name.
* @param array $attributes The tag attributes.
*
* @return string The begin tag.
*/
public static function beginTag(string $tag, array $attributes = []): string
{
$helperAttributes = new Attributes();
$tag = self::validateTag($tag);

if (self::inlinedElements($tag)) {
throw new \InvalidArgumentException('Inline elements cannot be used with begin/end syntax.');
}

return '<' . $tag . $helperAttributes->render($attributes) . '>';
}

/**
* This method creates a new HTML tag with the specified tag name, content, and attributes.
*
* @param string $tag The tag name.
* @param string $content The content of the tag.
* @param array $attributes The attributes of the tag.
*
* @return string The tag.
*/
public static function createTag(string $tag, string $content = '', array $attributes = []): string
{
$tag = self::validateTag($tag);
$voidElement = "<$tag" . Attributes::render($attributes) . '>';

if (self::voidElements($tag)) {
return $voidElement;
}

if (self::inlinedElements($tag)) {
return "$voidElement$content</$tag>";
}

$content = $content === '' ? '' : $content . PHP_EOL;

return "$voidElement\n$content</$tag>";
}

/**
* This method creates a new HTML end tag with the specified tag name.
*
* @param string $tag The tag name.
*
* @return string The closing tag.
*/
public static function endTag(string $tag): string
{
if (self::inlinedElements($tag)) {
throw new \InvalidArgumentException('Inline elements cannot be used with begin/end syntax.');
}

$tag = self::validateTag($tag);

return "</$tag>";
}

/**
* @return bool True if tag is inlined element.
*
* @link https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
*/
private static function inlinedElements(string $tag): bool
{
return in_array($tag, self::INLINE_ELEMENTS, true);
}

/**
* @return bool True if tag is void element.
*
* @link http://www.w3.org/TR/html-markup/syntax.html#void-element
*/
private static function voidElements(string $tag): bool
{
return in_array($tag, self::VOID_ELEMENT, true);
}

/**
* @throws \InvalidArgumentException
*/
private static function validateTag(string $tag): string
{
$tag = strtolower($tag);

if ($tag === '') {
throw new \InvalidArgumentException('Tag name cannot be empty.');
}

return $tag;
}
}
12 changes: 12 additions & 0 deletions src/HTMLBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace UIAwesome\Html\Helper;

/**
* This class provides methods to generate `HTML` code fragments programmatically.
*
* @link https://developer.mozilla.org/en-US/docs/Glossary/Element
*/
final class HTMLBuilder extends Base\AbstractHTMLBuilder {}
34 changes: 34 additions & 0 deletions tests/HTMLBuilderExceptionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace UIAwesome\Html\Tests\Helper;

use UIAwesome\Html\Helper\HTMLBuilder;

final class HTMLBuilderExceptionTest extends \PHPUnit\Framework\TestCase
{
public function testBeginInlineElement(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Inline elements cannot be used with begin/end syntax.');

HTMLBuilder::beginTag('br');
}

public function testEndInlineElement(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Inline elements cannot be used with begin/end syntax.');

HTMLBuilder::endTag('br');
}

public function testTagEmpty(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Tag name cannot be empty.');

HTMLBuilder::createTag('');
}
}
35 changes: 35 additions & 0 deletions tests/HTMLBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace UIAwesome\Html\Tests;

use PHPForge\Support\Assert;
use UIAwesome\Html\Helper\HTMLBuilder;

final class HTMLBuilderTest extends \PHPUnit\Framework\TestCase
{
public function testBegin(): void
{
$this->assertSame('<div>', HTMLBuilder::beginTag('div'));
$this->assertSame('<div class="class">', HTMLBuilder::beginTag('div', ['class' => 'class']));
}

/**
* @dataProvider UIAwesome\Html\Helper\Tests\Provider\TagProvider::create
*
* @param string $tagName Tag name.
* @param string $content Tag content.
* @param array $attributes Tag attributes.
* @param string $expected Expected result.
*/
public function testCreate(string $tagName, string $content, array $attributes, string $expected): void
{
Assert::equalsWithoutLE($expected, HTMLBuilder::createTag($tagName, $content, $attributes));
}

public function testEnd(): void
{
$this->assertSame('</div>', HTMLBuilder::endTag('div'));
}
}
42 changes: 42 additions & 0 deletions tests/Provider/TagProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace UIAwesome\Html\Helper\Tests\Provider;

final class TagProvider
{
public static function create(): array
{
return [
[
'article',
'',
[
'id' => 'id-1',
'class' => 'class',
],
'<article class="class" id="id-1">' . PHP_EOL . '</article>',
],
['br', '', [], '<br>'],
['BR', '', [], '<br>'],
['hr', '', [], '<hr>'],
['HR', '', [], '<hr>'],
['div', 'Content', [], '<div>' . PHP_EOL . 'Content' . PHP_EOL . '</div>'],
[
'input',
'',
[
'type' => 'text',
'name' => 'test',
'value' => '<>',
],
'<input name="test" type="text" value="&lt;&gt;">',
],
['span', '', [], '<span></span>'],
['span', '', [
'disabled' => true,
], '<span disabled></span>'],
];
}
}