Skip to content

[ENHANCEMENT] Migrate showForm() methods from raw HTML echo to Twig templates #50

@giovanny07

Description

@giovanny07

Plugin version: 3.2.6
GLPI version: 11.x
Priority: High
Files: src/Holiday.php, src/HolidayValidation.php, src/Config.php, src/HolidayCount.php, src/Profile.php, src/Preference.php, src/PlanningExternalEvent.php

Summary

The plugin currently renders all its forms by echoing raw HTML strings directly from PHP — over 512 echo "<..." statements across the source files. This was the standard pattern for GLPI 9/10 plugins, but GLPI 11 standardizes on Twig templates via TemplateRenderer.

Migrating to Twig would:

  • Make templates maintainable without touching PHP logic.
  • Enable GLPI 11's standard Bootstrap 5 form macros (fields_macros.html.twig), ensuring consistent UI with core GLPI.
  • Allow the plugin to benefit from GLPI's automatic CSRF injection, field accessibility, and responsive layout for free.
  • Dramatically reduce the PHP class sizes.

Current pattern (to be replaced)

// src/Holiday.php — showForm() — typical current pattern
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Begin date', 'activity') . "</td>";
echo "<td>";
Html::showDateField('begin', ['value' => $this->fields['begin']]);
echo "</td>";
echo "</tr>";
// ... hundreds more lines
Html::closeForm();

Target pattern (GLPI 11 standard)

PHP side — lean controller:

// src/Holiday.php — showForm() after migration
public function showForm($ID, array $options = []): bool
{
    $this->initForm($ID, $options);

    TemplateRenderer::getInstance()->display(
        '@activity/holiday_form.html.twig',
        [
            'item'       => $this,
            'params'     => $options,
            'holiday_types' => HolidayType::getAll(),
            'periods'       => HolidayPeriod::getForUser($this->fields['users_id'] ?? 0),
        ]
    );

    return true;
}

Twig template — templates/holiday_form.html.twig:

{# templates/holiday_form.html.twig #}
{% import 'components/form/fields_macros.html.twig' as fields %}

{% if item.isNewItem() %}
    {% set title = __('New holiday request', 'activity') %}
{% else %}
    {% set title = __('Holiday request', 'activity') ~ ' #' ~ item.getID() %}
{% endif %}

{{ include('components/form/header.html.twig', {'title': title}) }}

<div class="card-body row gap-3 flex-column">

    {{ fields.dropdownField(
        'users_id',
        item.fields['users_id'],
        'User'|itemtype_name,
        __('Applicant', 'activity'),
        {
            'disabled': not can_edit
        }
    ) }}

    {{ fields.dropdownField(
        'plugin_activity_holidaytypes_id',
        item.fields['plugin_activity_holidaytypes_id'],
        'GlpiPlugin\\Activity\\HolidayType'|itemtype_name,
        __('Holiday type', 'activity')
    ) }}

    {{ fields.dateField(
        'begin',
        item.fields['begin'],
        __('Begin date', 'activity')
    ) }}

    {{ fields.dateField(
        'end',
        item.fields['end'],
        __('End date', 'activity')
    ) }}

    {{ fields.textareaField(
        'comment',
        item.fields['comment'],
        __('Comment', 'activity')
    ) }}

</div>

{{ include('components/form/buttons.html.twig') }}

Migration checklist

  • src/Holiday.phpshowForm()
  • src/HolidayValidation.phpshowForm()
  • src/HolidayCount.phpshowForm()
  • src/Config.phpshowForm()
  • src/Profile.phpshowForm()
  • src/Preference.phpshowForm()
  • src/PlanningExternalEvent.php — inline HTML output
  • Create templates/ directory with one .html.twig per form
  • Remove all echo "<table class='tab_cadre_fixe'..., echo "<tr class='tab_bg_..." patterns

Notes

  • The migration can be done incrementally — one form at a time without breaking others.
  • tab_cadre_fixe, tab_bg_1, tab_bg_2 are GLPI 9/10 CSS classes that do not exist in GLPI 11. Twig macros output the correct Bootstrap 5 markup automatically.
  • Reference implementation: the holiday plugin by Teclib (inc/config.class.php + templates/config.html.twig) shows the complete pattern for a GLPI 11-compliant Twig form.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions