cphalcon icon indicating copy to clipboard operation
cphalcon copied to clipboard

[BUG]: html inputs have no way of being doctype aware ie html vs xhtml

Open Nialld opened this issue 8 months ago • 4 comments

Describe the bug Creating an instance of a Input form element (Hidden for example), there is no way for this to relate to the doctype of the document and render with or without closing slash

To Reproduce

Tag::setDocType(Tag::HTML5);
$hidden = new Hidden('test');
echo $hidden . PHP_EOL;

Tag::setDocType(Tag::XHTML5);
$hidden2 = new Hidden('test2');
echo $hidden2 . PHP_EOL;

Expected behavior should output

<input type="hidden" id="test" name="test">
<input type="hidden" id="test2" name="test2" />

Actual behavior outputs

<input type="hidden" id="test" name="test" />
<input type="hidden" id="test2" name="test2" />

Details

  • Phalcon version: 5.9.3
  • PHP Version: 8.4.8
  • Operating System:
  • Installation type: Ubuntu
  • Zephir version (if any):
  • Server: Nginx

Additional context this used to work in older version of phalcon as the Tag::setDocType(Tag::HTML5) was used when rendering tags but the phalcon/Html/Helper/Input/AbstractInput.zep __toString method now hardcodes the closing slash...

it appears that the Tag.zep code still does this type of thing correctly

if self::documentType > self::HTML5 { let code .= " />" . PHP_EOL; } else { let code .= ">" . PHP_EOL; }

but the rendering of inputs is not using this anymore?

this was reported when validating generated output via https://validator.w3.org/

Nialld avatar Jun 26 '25 11:06 Nialld

@niden the only way I could think of recreating the legacy support is to gain access to the container, get the tag , retrieve the loaded services for the tag factory and check the flag for doctype.

        $helper = container->get('tag');
        $helper->doctype(Doctype::XHTML5, PHP_EOL);

Then in the __toString and selfclose methods in the AbstractInput and AbstractHelper classes to verify if a doctype service exists and verify the flag used, recreating the similar effect as the legacy Tag class.

Do you think there are any other options?

raicabogdan avatar Jul 07 '25 12:07 raicabogdan

We can pass the parent class i.e. the tag factory and therefore access the service. That can be done in the constructor so it will be transparent.

Maybe also have a setter that will allow you to pass a different factory or a different doctype object?

niden avatar Jul 07 '25 12:07 niden

Factory

$this->newInstance($name, $this, ...$arguments);

and then in the Hidden helper for instance

public function __construct(private TagHelper $tagHelper)

Something like that

niden avatar Jul 07 '25 12:07 niden

@niden

it seems a bit disruptive to pass the factory class to each html elements instance, lots of tests fail. It works on my compiled version and receiving the output correctly, but I think it may break installation of users manually instantiating those html elements since those __construct() only expects the escaper.

If I'm to use the container to retrieve the factory services instead, would not disrupt instance creation, but would possible receive a warning stating they need to create a container first. Which if they use the helper , would have already created it. But again, tests don't use that either. I still think using the container is simpler, since they just need to instantiate DI wherever in their code before the html instance creation.

So whichever way I try, this update would create a disruption. Any thoughts ?

raicabogdan avatar Jul 08 '25 11:07 raicabogdan