Sindbad~EG File Manager

Current Path : /home/escuelai/public_html/it/marketplace/fields/inc/
Upload File :
Current File : /home/escuelai/public_html/it/marketplace/fields/inc/field.class.php

<?php

/**
 * -------------------------------------------------------------------------
 * Fields plugin for GLPI
 * -------------------------------------------------------------------------
 *
 * LICENSE
 *
 * This file is part of Fields.
 *
 * Fields is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Fields is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Fields. If not, see <http://www.gnu.org/licenses/>.
 * -------------------------------------------------------------------------
 * @copyright Copyright (C) 2013-2022 by Fields plugin team.
 * @license   GPLv2 https://www.gnu.org/licenses/gpl-2.0.html
 * @link      https://github.com/pluginsGLPI/fields
 * -------------------------------------------------------------------------
 */

use Glpi\Application\View\TemplateRenderer;
use Glpi\Toolbox\Sanitizer;

class PluginFieldsField extends CommonDBChild
{
    use Glpi\Features\Clonable;

    public static $itemtype = PluginFieldsContainer::class;
    public static $items_id = 'plugin_fields_containers_id';

    /**
     * Install or update fields
     *
     * @param Migration $migration Migration instance
     * @param string    $version   Plugin current version
     *
     * @return boolean
     */
    public static function install(Migration $migration, $version)
    {
        global $DB;

        $default_charset = DBConnection::getDefaultCharset();
        $default_collation = DBConnection::getDefaultCollation();
        $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption();

        $table = self::getTable();

        if (!$DB->tableExists($table)) {
            $migration->displayMessage(sprintf(__("Installing %s"), $table));

            $query = "CREATE TABLE IF NOT EXISTS `$table` (
                  `id`                                INT            {$default_key_sign} NOT NULL auto_increment,
                  `name`                              VARCHAR(255)   DEFAULT NULL,
                  `label`                             VARCHAR(255)   DEFAULT NULL,
                  `type`                              VARCHAR(255)    DEFAULT NULL,
                  `plugin_fields_containers_id`       INT            {$default_key_sign} NOT NULL DEFAULT '0',
                  `ranking`                           INT            NOT NULL DEFAULT '0',
                  `default_value`                     VARCHAR(255)   DEFAULT NULL,
                  `is_active`                         TINYINT        NOT NULL DEFAULT '1',
                  `is_readonly`                       TINYINT        NOT NULL DEFAULT '1',
                  `mandatory`                         TINYINT        NOT NULL DEFAULT '0',
                  `allowed_values`                    TEXT           ,
                  PRIMARY KEY                         (`id`),
                  KEY `plugin_fields_containers_id`   (`plugin_fields_containers_id`),
                  KEY `is_active`                     (`is_active`),
                  KEY `is_readonly`                   (`is_readonly`)
               ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;";
            $DB->query($query) or die($DB->error());
        }

        $migration->displayMessage("Updating $table");

        if (!$DB->fieldExists($table, 'is_active')) {
            $migration->addField($table, 'is_active', 'bool', ['value' => 1]);
            $migration->addKey($table, 'is_active', 'is_active');
        }
        if (!$DB->fieldExists($table, 'is_readonly')) {
            $migration->addField($table, 'is_readonly', 'bool', ['default' => false]);
            $migration->addKey($table, 'is_readonly', 'is_readonly');
        }
        if (!$DB->fieldExists($table, 'mandatory')) {
            $migration->addField($table, 'mandatory', 'bool', ['value' => 0]);
        }

        //increase the size of column 'type' (25 to 255)
        $migration->changeField($table, 'type', 'type', 'string');

        if (!$DB->fieldExists($table, 'allowed_values')) {
            $migration->addField($table, 'allowed_values', 'text');
        }

        $toolbox = new PluginFieldsToolbox();
        $toolbox->fixFieldsNames($migration, ['NOT' => ['type' => 'dropdown']]);

        //move old types to new format
        $migration->addPostQuery(
            $DB->buildUpdate(
                PluginFieldsField::getTable(),
                ['type' => 'dropdown-User'],
                ['type' => 'dropdownuser']
            )
        );

        $migration->addPostQuery(
            $DB->buildUpdate(
                PluginFieldsField::getTable(),
                ['type' => 'dropdown-OperatingSystem'],
                ['type' => 'dropdownoperatingsystems']
            )
        );

        return true;
    }

    public static function uninstall()
    {
        global $DB;

        $DB->query("DROP TABLE IF EXISTS `" . self::getTable() . "`");

        return true;
    }

    public static function getTypeName($nb = 0)
    {
        return __("Field", "fields");
    }


    public function prepareInputForAdd($input)
    {
        //parse name
        $input['name'] = $this->prepareName($input);

        //reject adding when field name is too long for mysql
        if (strlen($input['name']) > 64) {
            Session::AddMessageAfterRedirect(
                __("Field name is too long for database (digits in name are replaced by characters, try to remove them)", 'fields'),
                false,
                ERROR
            );
            return false;
        }

        if ($input['type'] === "dropdown") {
            //search if dropdown already exist in this container
            $found = $this->find(
                [
                    'name' => $input['name'],
                    'plugin_fields_containers_id' => $input['plugin_fields_containers_id'],
                ]
            );

            //reject adding for same dropdown on same bloc
            if (!empty($found)) {
                Session::AddMessageAfterRedirect(__("You cannot add same field 'dropdown' on same bloc", 'fields', false, ERROR));
                return false;
            }

            //reject adding when dropdown name is too long for mysql table name
            if (strlen(getTableForItemType(PluginFieldsDropdown::getClassname($input['name']))) > 64) {
                Session::AddMessageAfterRedirect(
                    __("Field name is too long for database (digits in name are replaced by characters, try to remove them)", 'fields'),
                    false,
                    ERROR
                );
                return false;
            }
        }

        // Before adding, add the ranking of the new field
        if (empty($input["ranking"])) {
            $input["ranking"] = $this->getNextRanking();
        }

        //add field to container table
        if ($input['type'] !== "header") {
            $container_obj = new PluginFieldsContainer();
            $container_obj->getFromDB($input['plugin_fields_containers_id']);
            foreach (json_decode($container_obj->fields['itemtypes']) as $itemtype) {
                $classname = PluginFieldsContainer::getClassname($itemtype, $container_obj->fields['name']);
                $classname::addField($input['name'], $input['type']);
            }
        }

        if (isset($input['allowed_values'])) {
            $input['allowed_values'] = Sanitizer::dbEscape(json_encode($input['allowed_values']));
        }

        return $input;
    }

    // phpcs:ignore PSR1.Methods.CamelCapsMethodName
    public function pre_deleteItem()
    {
        //remove field in container table
        if (
            $this->fields['type'] !== "header"
            && !isset($_SESSION['uninstall_fields'])
            && !isset($_SESSION['delete_container'])
        ) {
            $container_obj = new PluginFieldsContainer();
            $container_obj->getFromDB($this->fields['plugin_fields_containers_id']);
            foreach (json_decode($container_obj->fields['itemtypes']) as $itemtype) {
                $classname = PluginFieldsContainer::getClassname($itemtype, $container_obj->fields['name']);
                $classname::removeField($this->fields['name'], $this->fields['type']);
            }
        }

        //delete label translations
        $translation_obj = new PluginFieldsLabelTranslation();
        $translation_obj->deleteByCriteria([
            'itemtype' => self::getType(),
            'items_id' => $this->fields['id']
        ]);

        if ($this->fields['type'] === "dropdown") {
            return PluginFieldsDropdown::destroy($this->fields['name']);
        }
        return true;
    }

    // phpcs:ignore PSR1.Methods.CamelCapsMethodName
    public function post_purgeItem()
    {
        global $DB;

        $table         = getTableForItemType(__CLASS__);
        $old_container = $this->fields['plugin_fields_containers_id'];
        $old_ranking   = $this->fields['ranking'];

        $query = "UPDATE $table SET
                ranking = ranking-1
                WHERE plugin_fields_containers_id = $old_container
                AND ranking > $old_ranking";
        $DB->query($query);

        return true;
    }


    /**
     * parse name for avoid non alphanumeric char in it and conflict with other fields
     * @param  array $input the field form input
     * @return string  the parsed name
     */
    public function prepareName($input)
    {
        $toolbox = new PluginFieldsToolbox();

        //contruct field name by processing label (remove non alphanumeric char)
        if (empty($input['name'])) {
            $input['name'] = $toolbox->getSystemNameFromLabel($input['label']) . 'field';
        }

        //for dropdown, if already exist, link to it
        if (isset($input['type']) && $input['type'] === "dropdown") {
            $found = $this->find(['name' => $input['name']]);
            if (!empty($found)) {
                return $input['name'];
            }
        }

        //check if field name not already exist and not in conflict with itemtype fields name
        $container = new PluginFieldsContainer();
        $container->getFromDB($input['plugin_fields_containers_id']);

        $field      = new self();
        $field_name = $input['name'];
        $i = 2;
        while (count($field->find(['name' => $field_name])) > 0) {
            $field_name = $toolbox->getIncrementedSystemName($input['name'], $i);
            $i++;
        }

        return $field_name;
    }

    /**
     * Get the next ranking for a specified field
     *
     * @return integer
     */
    public function getNextRanking()
    {
        global $DB;

        $sql = "SELECT max(`ranking`) AS `rank`
              FROM `" . self::getTable() . "`
              WHERE `plugin_fields_containers_id` = '" .
                  $this->fields['plugin_fields_containers_id'] . "'";
        $result = $DB->query($sql);

        if ($DB->numrows($result) > 0) {
            $data = $DB->fetchAssoc($result);
            return $data["rank"] + 1;
        }
        return 0;
    }

    public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0)
    {
        if (!$withtemplate) {
            switch ($item->getType()) {
                case __CLASS__:
                    $ong[1] = $this->getTypeName(1);
                    return $ong;
            }
        }

        return self::createTabEntry(
            __("Fields", "fields"),
            countElementsInTable(
                self::getTable(),
                ['plugin_fields_containers_id' => $item->getID()]
            )
        );
    }

    public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0)
    {
        $fup = new self();
        $fup->showSummary($item);
        return true;
    }

    public function defineTabs($options = [])
    {
        $ong = [];
        $this->addDefaultFormTab($ong);
        $this->addStandardTab('PluginFieldsLabelTranslation', $ong, $options);

        return $ong;
    }

    public function showSummary($container)
    {
        global $DB, $CFG_GLPI;

        $cID = $container->fields['id'];

        // Display existing Fields
        $query  = "SELECT `id`, `label`
                FROM `" . $this->getTable() . "`
                WHERE `plugin_fields_containers_id` = '$cID'
                ORDER BY `ranking` ASC";
        $result = $DB->query($query);

        $rand   = mt_rand();

        echo "<div id='viewField$cID$rand'></div>";

        $ajax_params = [
            'type'                        => __CLASS__,
            'parenttype'                  => PluginFieldsContainer::class,
            'plugin_fields_containers_id' => $cID,
            'id'                          => -1
        ];
        echo Html::scriptBlock('
            viewAddField' . $cID . $rand . ' = function() {
                $("#viewField' . $cID . $rand . '").load(
                    "' . $CFG_GLPI['root_doc'] . '/ajax/viewsubitem.php",
                    ' . json_encode($ajax_params) . '
                );
            };
        ');

        echo "<div class='center'>" .
           "<a href='javascript:viewAddField$cID$rand();'>";
        echo __("Add a new field", "fields") . "</a></div><br>";

        if ($DB->numrows($result) == 0) {
            echo "<table class='tab_cadre_fixe'><tr class='tab_bg_2'>";
            echo "<th class='b'>" . __("No field for this block", "fields") . "</th></tr></table>";
        } else {
            echo '<div id="drag">';
            echo Html::hidden("_plugin_fields_containers_id", ['value' => $cID,
                'id'    => 'plugin_fields_containers_id'
            ]);
            echo "<table class='tab_cadre_fixehov'>";
            echo "<tr>";
            echo "<th>" . __("Label")              . "</th>";
            echo "<th>" . __("Type")               . "</th>";
            echo "<th>" . __("Default values")     . "</th>";
            echo "<th>" . __("Mandatory field")    . "</th>";
            echo "<th>" . __("Active")             . "</th>";
            echo "<th>" . __("Read only", "fields") . "</th>";
            echo "<th width='16'>&nbsp;</th>";
            echo "</tr>";

            $fields_type = self::getTypes();

            Session::initNavigateListItems('PluginFieldsField', __('Fields list'));

            while ($data = $DB->fetchArray($result)) {
                if ($this->getFromDB($data['id'])) {
                    echo "<tr class='tab_bg_2' style='cursor:pointer'>";

                    echo "<td>";
                    echo "<a href='" . Plugin::getWebDir('fields') . "/front/field.form.php?id={$this->getID()}'>{$this->fields['label']}</a>";
                    echo "</td>";
                    echo "<td>" . $fields_type[$this->fields['type']] . "</td>";
                    echo "<td>" . $this->fields['default_value'] . "</td>";
                    echo "<td align='center'>" . Dropdown::getYesNo($this->fields["mandatory"]) . "</td>";
                    echo "<td align='center'>";
                    echo ($this->isActive())
                     ? __('Yes')
                     : '<b class="red">' . __('No') . '</b>';
                    echo "</td>";

                    echo "<td>";
                    echo Dropdown::getYesNo($this->fields["is_readonly"]);
                    echo "</td>";

                    echo '<td class="rowhandler control center">';
                    echo '<div class="drag row" style="cursor:move; border: 0;">';
                    echo '<i class="ti ti-grip-horizontal" title="' . __('Move') . '">';
                    echo '</div>';
                    echo '</td>';
                    echo "</tr>";
                }
            }
        }
        echo '</table>';
        echo '</div>';
        echo Html::scriptBlock('$(document).ready(function() {
            redipsInit()
        });');
    }


    public function showForm($ID, $options = [])
    {
        global $CFG_GLPI;

        $rand = mt_rand();

        if (isset($options['parent_id']) && !empty($options['parent_id'])) {
            $container = new PluginFieldsContainer();
            $container->getFromDB($options['parent_id']);
        } else if (
            isset($options['parent'])
                 && $options['parent'] instanceof CommonDBTM
        ) {
            $container = $options['parent'];
        }

        if ($ID > 0) {
            $attrs = ['readonly' => 'readonly'];
            $edit = true;
        } else {
            $attrs = [];
            // Create item
            $edit = false;
            $options['plugin_fields_containers_id'] = $container->getField('id');
        }

        $this->initForm($ID, $options);
        $this->showFormHeader($ID, $options);

        echo "<tr>";
        echo "<td>" . __("Label") . " : </td>";
        echo "<td colspan='3'>";
        echo Html::hidden('plugin_fields_containers_id', ['value' => $container->getField('id')]);
        echo Html::input(
            'label',
            [
                'value' => $this->fields['label'],
            ] + $attrs
        );
        echo "</td>";

        echo "</tr>";
        echo "<tr>";
        echo "<td>" . __("Type") . " : </td>";
        echo "<td colspan='3'>";
        if ($edit) {
            echo self::getTypes(true)[$this->fields['type']];
        } else {
            // if glpi_item selected display dropdown and hide input default_value
            echo Html::scriptBlock(<<<JAVASCRIPT
                var plugin_fields_change_field_type_{$rand} = function(selected_val) {
                    if (selected_val === 'glpi_item') {
                        $('#plugin_fields_default_value_label_{$rand}').hide();
                        $('#plugin_fields_default_value_field_{$rand}').find('[name="default_value"]').val(null).trigger('change');
                        $('#plugin_fields_default_value_field_{$rand}').hide();
                        $('#plugin_fields_allowed_values_label_{$rand}').show();
                        $('#plugin_fields_allowed_values_field_{$rand}').show();
                    } else {
                        $('#plugin_fields_default_value_label_{$rand}').show();
                        $('#plugin_fields_default_value_field_{$rand}').show();
                        $('#plugin_fields_allowed_values_label_{$rand}').hide();
                        $('#plugin_fields_allowed_values_field_{$rand}').find('[name="allowed_values\[\]"]').val(null).trigger('change');
                        $('#plugin_fields_allowed_values_field_{$rand}').hide();
                    }
                };
                $(
                    function () {
                        plugin_fields_change_field_type_{$rand}();
                    }
                );
JAVASCRIPT
            );

            // Exclude dropdown that corresponds to itemtypes targetted by container.
            // This will prevent issues with search options.
            // FIXME: Fix search options handling and remove this limitation.
            $itemtypes_to_exclude = !empty($container->fields['itemtypes'])
                ? array_map(
                    function ($itemtype) {
                        return 'dropdown-' . $itemtype;
                    },
                    json_decode($container->fields['itemtypes'])
                )
                : [];
            Dropdown::showFromArray(
                'type',
                self::getTypes(false),
                [
                    'value'     => $this->fields['type'],
                    'on_change' => 'plugin_fields_change_field_type_' . $rand . '(this.value)',
                    'used'      => array_combine($itemtypes_to_exclude, $itemtypes_to_exclude),
                ]
            );
        }
        echo "</td>";
        echo "</tr>";

        $style_default = $this->fields['type'] === 'glpi_item' ? 'style="display:none;"' : '';
        $style_allowed = $this->fields['type'] !== 'glpi_item' ? 'style="display:none;"' : '';
        echo "<tr>";
        echo "<td>";
        echo '<div id="plugin_fields_default_value_label_' . $rand . '" ' . $style_default . '>';
        echo __("Default values") . " : ";
        echo '</div>';
        echo '<div id="plugin_fields_allowed_values_label_' . $rand . '" ' . $style_allowed . '>';
        echo __('Allowed values', 'fields') . " : ";
        echo '</div>';
        echo "</td>";
        echo "<td colspan='3'>";
        echo '<div id="plugin_fields_default_value_field_' . $rand . '" ' . $style_default . '>';
        echo Html::input(
            'default_value',
            [
                'value' => $this->fields['default_value'],
            ]
        );
        if ($this->fields["type"] == "dropdown") {
            echo '<a href="' . Plugin::getWebDir('fields') . '/front/commondropdown.php?ddtype=' .
                          $this->fields['name'] . 'dropdown">
               <img src="' . $CFG_GLPI['root_doc'] . '/pics/options_search.png" class="pointer"
                    alt="' . __('Configure', 'fields') . '" title="' . __('Configure fields values', 'fields') . '">
               </a>';
        }
        if (in_array($this->fields['type'], ['date', 'datetime'])) {
            echo "<i class='pointer fa fa-info'
                  title=\"" . __("You can use 'now' for date and datetime field") . "\"></i>";
        }
        echo '</div>';
        echo '<div id="plugin_fields_allowed_values_field_' . $rand . '" ' . $style_allowed . '>';
        if (!$edit) {
            Dropdown::showFromArray('allowed_values', PluginFieldsToolbox::getGlpiItemtypes(), [
                'display_emptychoice'   => true,
                'multiple' => true
            ]);
        } else {
            $allowed_itemtypes = !empty($this->fields['allowed_values'])
            ? json_decode($this->fields['allowed_values'])
            : [];
            echo implode(
                ', ',
                array_map(
                    function ($itemtype) {
                        return is_a($itemtype, CommonDBTM::class, true)
                        ? $itemtype::getTypeName(Session::getPluralNumber())
                        : $itemtype;
                    },
                    $allowed_itemtypes
                )
            );
        }
        echo '</div>';
        echo "</td>";
        echo "</tr>";

        echo "<tr>";
        echo "<td>" . __('Active') . " :</td>";
        echo "<td>";
        Dropdown::showYesNo('is_active', $this->fields["is_active"]);
        echo "</td>";
        echo "<td>" . __("Mandatory field") . " : </td>";
        echo "<td>";
        Dropdown::showYesNo("mandatory", $this->fields["mandatory"]);
        echo "</td>";
        echo "</tr>";

        echo "<tr>";
        echo "<td>" . __("Read only", "fields") . " :</td>";
        echo "<td colspan='3'>";
        Dropdown::showYesNo("is_readonly", $this->fields["is_readonly"]);
        echo "</td>";
        echo "</tr>";

        $this->showFormButtons($options);
    }

    public static function showForTabContainer($c_id, $item)
    {
        //profile restriction (for reading profile)
        $profile = new PluginFieldsProfile();
        $found = $profile->find(['profiles_id' => $_SESSION['glpiactiveprofile']['id'],
            'plugin_fields_containers_id' => $c_id
        ]);
        $first_found = array_shift($found);
        $canedit = ($first_found['right'] == CREATE);

        //get fields for this container
        $field_obj = new self();
        $fields = $field_obj->find(['plugin_fields_containers_id' => $c_id, 'is_active' => 1], "ranking");
        echo "<form method='POST' action='" . Plugin::getWebDir('fields') . "/front/container.form.php'>";
        echo Html::hidden('plugin_fields_containers_id', ['value' => $c_id]);
        echo Html::hidden('items_id', ['value' => $item->getID()]);
        echo Html::hidden('itemtype', ['value' => $item->getType()]);
        echo "<table class='tab_cadre_fixe'>";
        echo self::prepareHtmlFields($fields, $item, $canedit);

        if ($canedit) {
            echo "<tr><td class='tab_bg_2 center' colspan='4'>";
            echo "<input class='btn btn-primary' type='submit' name='update_fields_values' value=\"" .
            _sx("button", "Save") . "\" class='submit'>";
            echo "</td></tr>";
        }

        echo "</table>";
        Html::closeForm();

        return true;
    }

    /**
     * Display dom container
     *
     * @param int         $id       Container's ID
     * @param CommonDBTM  $item     Item
     * @param string      $type     Type (either 'dom' or 'domtab'
     * @param string      $subtype  Requested subtype (used for domtab only)
     *
     * @return void
     */
    public static function showDomContainer($id, $item, $type = "dom", $subtype = "")
    {

        if ($id !== false) {
            //get fields for this container
            $field_obj = new self();
            $fields = $field_obj->find(
                [
                    'plugin_fields_containers_id' => $id,
                    'is_active' => 1,
                ],
                "ranking"
            );
        } else {
            $fields = [];
        }

        echo Html::hidden('_plugin_fields_type', ['value' => $type]);
        echo Html::hidden('_plugin_fields_subtype', ['value' => $subtype]);
        echo self::prepareHtmlFields($fields, $item);
    }

    /**
     * Display fields in any existing tab
     *
     * @param array $params [item, options]
     *
     * @return void
     */
    public static function showForTab($params)
    {
        $item = $params['item'];

        $functions = array_column(debug_backtrace(), 'function');

        $subtype = isset($_SESSION['glpi_tabs'][strtolower($item::getType())]) ? $_SESSION['glpi_tabs'][strtolower($item::getType())] : "";
        $type = substr($subtype, -strlen('$main')) === '$main'
            || in_array('showForm', $functions)
            || in_array('showPrimaryForm', $functions)
            || in_array('showFormHelpdesk', $functions)
                ? 'dom'
                : 'domtab';
        if ($subtype == -1) {
            $type = 'dom';
        }
        // if we are in 'dom' or 'tab' type, no need for subtype ('domtab' specific)
        if ($type != 'domtab') {
            $subtype = "";
        }
        //find container (if not exist, do nothing)
        if (isset($_REQUEST['c_id'])) {
            $c_id = $_REQUEST['c_id'];
        } else if (!$c_id = PluginFieldsContainer::findContainer(get_Class($item), $type, $subtype)) {
            return false;
        }

        //need to check if container is usable on this object entity
        $loc_c = new PluginFieldsContainer();
        $loc_c->getFromDB($c_id);
        $entities = [$loc_c->fields['entities_id']];
        if ($loc_c->fields['is_recursive']) {
            $entities = getSonsOf(getTableForItemType('Entity'), $loc_c->fields['entities_id']);
        }

        if ($item->isEntityAssign()) {
            $current_entity = $item->getEntityID();
            if (!in_array($current_entity, $entities)) {
                return false;
            }
        }

        //parse REQUEST_URI
        if (!isset($_SERVER['REQUEST_URI'])) {
            return false;
        }
        $current_url = $_SERVER['REQUEST_URI'];
        if (
            strpos($current_url, ".form.php") === false
            && strpos($current_url, ".injector.php") === false
            && strpos($current_url, ".public.php") === false
        ) {
            return false;
        }

        //Retrieve dom container
        $itemtypes = PluginFieldsContainer::getUsedItemtypes($type, true);

        //if no dom containers defined for this itemtype, do nothing (in_array case insensitive)
        if (!in_array(strtolower($item::getType()), array_map('strtolower', $itemtypes))) {
            return false;
        }

        $html_id = 'plugin_fields_container_' . mt_rand();
        echo "<div id='{$html_id}'>";
        $display_condition = new PluginFieldsContainerDisplayCondition();
        if ($display_condition->computeDisplayContainer($item, $c_id)) {
            self::showDomContainer(
                $c_id,
                $item,
                $type,
                $subtype
            );
        }
        echo "</div>";

        //JS to trigger any change and check if container need to be display or not
        $ajax_url   = Plugin::getWebDir('fields') . '/ajax/container.php';
        $items_id = !$item->isNewItem() ? $item->getID() : 0;
        echo Html::scriptBlock(<<<JAVASCRIPT
            function refreshContainer() {
                const data = $('#{$html_id}').closest('form').serializeArray().reduce(
                    function(obj, item) {
                        obj[item.name] = item.value;
                        return obj;
                    },
                    {}
                );

                $.ajax(
                    {
                        url: '{$ajax_url}',
                        type: 'GET',
                        data: {
                            action:   'get_fields_html',
                            id:       {$c_id},
                            itemtype: '{$item::getType()}',
                            items_id: {$items_id},
                            type:     '{$type}',
                            subtype:  '{$subtype}',
                            input:    data
                        },
                        success: function(data) {
                            // Close open select2 dropdown that will be replaced
                            $('#{$html_id}').find('.select2-hidden-accessible').select2('close');
                            // Refresh fields HTML
                            $('#{$html_id}').html(data);
                        }
                    }
                );
            }
            $(
                function () {
                    const form = $('#{$html_id}').closest('form');
                    form.on(
                        'change',
                        'input, select, textarea',
                        function(evt) {
                            if ($(evt.target).closest('#{$html_id}').length > 0) {
                                return; // Do nothing if element is inside fields container
                            }
                            refreshContainer();
                        }
                    );

                    var refresh_timeout = null;
                    form.find('textarea').each(
                        function () {
                            const editor = tinymce.get(this.id);
                            if (editor !== null) {
                                editor.on(
                                    'change',
                                    function(evt) {
                                        if ($(evt.target.targetElm).closest('#{$html_id}').length > 0) {
                                            return; // Do nothing if element is inside fields container
                                        }

                                        if (refresh_timeout !== null) {
                                            window.clearTimeout(refresh_timeout);
                                        }
                                        refresh_timeout = window.setTimeout(refreshContainer, 1000);
                                    }
                                );
                            }
                        }
                    );
                }
            );
JAVASCRIPT
        );
    }

    public static function prepareHtmlFields(
        $fields,
        $item,
        $canedit = true,
        $show_table = true,
        $massiveaction = false
    ) {

        if (empty($fields)) {
            return false;
        }

        //get object associated with this fields
        $tmp = $fields;
        $first_field = array_shift($tmp);
        $container_obj = new PluginFieldsContainer();
        $container_obj->getFromDB($first_field['plugin_fields_containers_id']);

        // Fill status overrides if needed
        if (in_array($item->getType(), PluginFieldsStatusOverride::getStatusItemtypes())) {
            $status_overrides = PluginFieldsStatusOverride::getOverridesForItem($container_obj->getID(), $item);
            foreach ($status_overrides as $status_override) {
                if (isset($fields[$status_override['plugin_fields_fields_id']])) {
                    $fields[$status_override['plugin_fields_fields_id']]['is_readonly'] = $status_override['is_readonly'];
                    $fields[$status_override['plugin_fields_fields_id']]['mandatory'] = $status_override['mandatory'];
                }
            }
        }

        $found_v = null;
        if (!$item->isNewItem()) {
            //find row for this object with the items_id
            $classname = PluginFieldsContainer::getClassname($item->getType(), $container_obj->fields['name']);
            $obj = new $classname();
            $found_values = $obj->find(
                [
                    'plugin_fields_containers_id' => $first_field['plugin_fields_containers_id'],
                    'items_id' => $item->getID(),
                ]
            );
            $found_v = array_shift($found_values);
        }

        // find profiles (to check if current profile can edit fields)
        $fprofile = new PluginFieldsProfile();
        $found_p = $fprofile->find(
            [
                'profiles_id' => $_SESSION['glpiactiveprofile']['id'],
                'plugin_fields_containers_id' => $first_field['plugin_fields_containers_id'],
            ]
        );
        $first_found_p = array_shift($found_p);

        // test status for "CommonITILObject" objects
        if ($item instanceof CommonITILObject) {
            $status = $item->fields['status'] ?? null;
            if (
                ($status !== null && in_array($status, $item->getClosedStatusArray()))
                || $first_found_p['right'] != CREATE
            ) {
                $canedit = false;
            }
        } else {
            if ($first_found_p['right'] != CREATE) {
                $canedit = false;
            }
        }

        //show all fields
        foreach ($fields as &$field) {
            $field['itemtype'] = self::getType();
            $field['label'] = PluginFieldsLabelTranslation::getLabelFor($field);

            $field['allowed_values'] = !empty($field['allowed_values']) ? json_decode($field['allowed_values']) : [];
            if ($field['type'] === 'glpi_item') {
               // Convert allowed values to [$itemtype_class => $itemtype_name] format
                $allowed_itemtypes = [];
                foreach ($field['allowed_values'] as $allowed_itemtype) {
                    if (is_a($allowed_itemtype, CommonDBTM::class, true)) {
                        $allowed_itemtypes[$allowed_itemtype] = $allowed_itemtype::getTypeName(Session::getPluralNumber());
                    }
                }
                $field['allowed_values'] = $allowed_itemtypes;
            }

            //compute classname for 'dropdown-XXXXXX' field
            $dropdown_matches = [];
            if (
                preg_match('/^dropdown-(?<class>.+)$/i', $field['type'], $dropdown_matches)
                && class_exists($dropdown_matches['class'])
            ) {
                $dropdown_class = $dropdown_matches['class'];

                $field['dropdown_class'] = $dropdown_class;
                $field['dropdown_condition'] = [];

                $object = new $dropdown_class();
                if ($object->maybeDeleted()) {
                    $field['dropdown_condition']['is_deleted'] = false;
                }
                if ($object->maybeActive()) {
                    $field['dropdown_condition']['is_active'] = true;
                }
            }

            //get value
            $value = null;
            if (is_array($found_v)) {
                if ($field['type'] == "dropdown") {
                    $value = $found_v["plugin_fields_" . $field['name'] . "dropdowns_id"];
                } else if ($field['type'] == "glpi_item") {
                    $itemtype_key = sprintf('itemtype_%s', $field['name']);
                    $items_id_key = sprintf('items_id_%s', $field['name']);
                    $value = [
                        'itemtype' => $found_v[$itemtype_key],
                        'items_id' => $found_v[$items_id_key],
                    ];
                } else {
                    $value = $found_v[$field['name']] ?? "";
                }
            }

            if (!$field['is_readonly']) {
                if ($field['type'] == "dropdown") {
                    if (
                        isset($_SESSION['plugin']['fields']['values_sent']["plugin_fields_" .
                                                                     $field['name'] .
                                                                     "dropdowns_id"])
                    ) {
                        $value = $_SESSION['plugin']['fields']['values_sent']["plugin_fields_" .
                                                                        $field['name'] .
                                                                        "dropdowns_id"];
                    }
                } else if (isset($_SESSION['plugin']['fields']['values_sent'][$field['name']])) {
                    $value = $_SESSION['plugin']['fields']['values_sent'][$field['name']];
                }
            }

            //get default value
            if ($value === null) {
                if ($field['type'] === 'dropdown' && $field['default_value'] === '') {
                    $value = 0;
                } else if ($field['default_value'] !== "") {
                    $value = $field['default_value'];

                    // shortcut for date/datetime
                    if (
                        in_array($field['type'], ['date', 'datetime'])
                        && $value == 'now'
                    ) {
                        $value = $_SESSION["glpi_currenttime"];
                    }
                }
            }

            $field['value'] = $value;
        }

        $html = TemplateRenderer::getInstance()->render('@fields/fields.html.twig', [
            'item'           => $item,
            'fields'         => $fields,
            'canedit'        => $canedit,
            'massiveaction'  => $massiveaction,
            'container'      => $container_obj,
        ]);

        unset($_SESSION['plugin']['fields']['values_sent']);

        return $html;
    }

    public static function showSingle($itemtype, $searchOption, $massiveaction = false)
    {
        global $DB;

        //clean dropdown [pre/su]fix if exists
        $cleaned_linkfield = preg_replace(
            "/plugin_fields_(.*)dropdowns_id/",
            "$1",
            $searchOption['linkfield']
        );

        //find field
        $query = "SELECT fields.plugin_fields_containers_id, fields.is_readonly, fields.default_value
                FROM glpi_plugin_fields_fields fields
                LEFT JOIN glpi_plugin_fields_containers containers
                  ON containers.id = fields.plugin_fields_containers_id
                  AND containers.itemtypes LIKE '%$itemtype%'
               WHERE fields.name = '$cleaned_linkfield'";
        $res = $DB->query($query);
        if ($DB->numrows($res) == 0) {
            return false;
        }

        $data = $DB->fetchAssoc($res);

        //display an hidden post field to store container id
        echo Html::hidden('c_id', ['value' => $data['plugin_fields_containers_id']]);

        //prepare array for function prepareHtmlFields
        $fields = [[
            'id'                          => 0,
            'type'                        => $searchOption['pfields_type'],
            'plugin_fields_containers_id' => $data['plugin_fields_containers_id'],
            'name'                        => $cleaned_linkfield,
            'is_readonly'                 => $data['is_readonly'],
            'default_value'               => $data['default_value']
        ]
        ];

        //show field
        $item = new $itemtype();
        $item->getEmpty();

        echo self::prepareHtmlFields($fields, $item, true, false, $massiveaction);

        return true;
    }

    // phpcs:ignore PSR1.Methods.CamelCapsMethodName
    public function post_getEmpty()
    {
        $this->fields['is_active'] = 1;
        $this->fields['type']      = 'text';
    }

    public static function getTypes(bool $flat_list = true)
    {
        $common_types = [
            'header'       => __("Header", "fields"),
            'text'         => __("Text (single line)", "fields"),
            'textarea'     => __("Text (multiples lines)", "fields"),
            'number'       => __("Number", "fields"),
            'url'          => __("URL", "fields"),
            'dropdown'     => __("Dropdown", "fields"),
            'yesno'        => __("Yes/No", "fields"),
            'date'         => __("Date", "fields"),
            'datetime'     => __("Date & time", "fields"),
            'glpi_item'    => __("GLPI item", "fields"),
        ];

        $all_types = [
            __('Common') => $common_types,
        ];

        foreach (PluginFieldsToolbox::getGlpiItemtypes() as $section => $itemtypes) {
            $all_types[$section] = [];
            foreach ($itemtypes as $itemtype => $itemtype_name) {
                $all_types[$section]['dropdown-' . $itemtype] = $itemtype_name;
            }
        }

        return $flat_list ? array_merge([], ...array_values($all_types)) : $all_types;
    }

    // phpcs:ignore PSR1.Methods.CamelCapsMethodName
    public function post_addItem()
    {
        $input = $this->fields;

        //dropdowns : create files
        if ($input['type'] === "dropdown") {
            //search if dropdown already exist in other container
            $found = $this->find(['id' => ['!=', $input['id']], 'name' => $input['name']]);
            //for dropdown, if already exist, don't create files
            if (empty($found)) {
                PluginFieldsDropdown::create($input);
            }
        }

        //Create label translation
        if (!isset($this->input['clone']) || !$this->input['clone']) {
            PluginFieldsLabelTranslation::createForItem($this);
        }
    }

    public function rawSearchOptions()
    {
        $tab = [];

        $tab[] = [
            'id'            => 2,
            'table'         => self::getTable(),
            'field'         => 'label',
            'name'          => __('Label'),
            'massiveaction' => false,
            'autocomplete'  => true,
        ];

        $tab[] = [
            'id'            => 3,
            'table'         => self::getTable(),
            'field'         => 'default_value',
            'name'          => __('Default values'),
            'massiveaction' => false,
            'autocomplete'  => true,
        ];

        return $tab;
    }

    public function prepareInputForClone($input)
    {
        if (array_key_exists('allowed_values', $input) && !empty($input['allowed_values'])) {
            // $input has been transformed with `Toolbox::addslashes_deep()`, and `self::prepareInputForAdd()`
            // is expecting an array, so it have to be unslashed then json decoded.
            $input['allowed_values'] = json_decode(Sanitizer::dbUnescape($input['allowed_values']));
        } else {
            unset($input['allowed_values']);
        }

        return $input;
    }

    public function getCloneRelations(): array
    {
        return [
            PluginFieldsStatusOverride::class,
            PluginFieldsLabelTranslation::class,
        ];
    }
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists