<?php
/**
 * Funktionalität zur Optimierung der Laravel/Livewire Fehlermeldungen für Formulare
 *
 * @todo        - Eventuell könnten hier auch noch QueryExceptions behandelt werden (siehe auch
 *                UserForm::save()).
 *
 * @version     1.0.$Revision:$
 * @version     SVN: $Id:$
 * @package     bplan-base/globals
 * @subpackage  Traits
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 * @copyright   Copyright (C) 2025, 2026 bplan-solutions GmbH & Co. KG <http://www.bplan-solutions.de/>
 * /Δ\
 */

namespace BplanBase\Globals\Traits\Core;


/**
 * Funktionalität zur Optimierung der Laravel/Livewire Fehlermeldungen für Formulare
 *
 * ACHTUNG
 * Diese Anleitung ist nicht mehr aif dem aktuellen Stand.
 *
 * Dieser Trait kann via "use" in einer Livewire-Komponente eingebunden werden um seine Funktionalität
 * dort verfügbar zu machen.
 *
 * Beispiel:
 *
 * <pre>
 *   <code>
 *      use BplanBase\Globals\Livewire\ValidationTrait;
 *&nbsp;
 *      class UserForm extends Component
 *      {
 *          use ValidationTrait;
 *          ...
 *      }
 *   </code>
 * </pre>
 *
 * Alternativ zur direkten Verwendung dieses Traits, kann die zu erweiternde Component aber auch
 * von der Klasse "FormComponentBase" (@see App\bplan\Livewire\FormComponentBase) abgeleitet werden
 * (nur für Formular-Klassen sinnvoll). Diese Klasse hat die Verwendung dieses Traits bereits
 * implementiert.
 *
 *
 *   <strong>Erläuterungen</strong>
 *
 * Mit der Installation von Livewire wird auch die Locale-Datei "validation.php" installiert. Darin
 * sind Fehlermeldungen, passend zu den Validation Rules von Laravel, definiert. Allerdings wird in
 * diesen Fehlermeldungen immer der interne Feldname (Variablenname) verwendet, um das Feld zu
 * benennen. Für den Endanwender ist das unter Umständen nichtssagend oder sogar verwirrend.
 *
 * Diese Erweiterung schafft Möglichkeit eigene Standardfehlermeldungen (passend zu einer Rule) oder
 * auch vollständig individuelle Fehlermeldungen zu definieren, in denen das Label des jeweiligen
 * Eingabefeldes (also das was der User auch im Formular sieht) verwendet wird.
 *
 *   <strong>Anwendung</strong>
 *
 * Eigene Standardfehlermeldungen werden in der Locale-Datei "global.php" (lang/#/global.php)
 * definiert. Der Schlüssel der Fehlermeldungen muss dabei immer aus dem Präfix "form-error" und der
 * Laravel Validation-Rule (@see https://laravel.com/docs/9.x/validation#available-validation-rules),
 * getrennt durch einen Punkt (.), gebildet werden.
 *
 * Beispiele:
 *
 *  <pre>
 *    <code>
 *      'form-error.integer'  => 'Im Feld ":attribute" wird eine Ganzzahl erwartet.',
 *      'form-error.required' => 'Das Feld ":attribute" ist ein Pflichtfeld.',
 *    </code>
 *  </pre>
 * Um den Platzhalter ":attribute" zur Laufzeit durch das im Formular verwendete Label ersetzen zu
 * können, müssen auch die Schlüssel der Label in einem speziellen Format angelegt werdn.
 * Jeder Schlüssel muss aus dem Präfix "label", einem Punkt (.) und dem Variablennamen zusammengesetzt
 * werden.
 *
 * Beispiele:
 *
 *  <pre>
 *    <code>
 *      'label.email'                 => 'E-Mail Adresse',
 *      'label.organizationalunit_id' => 'Organisationseinheit',
 *    </code>
 *  </pre>
 * Damit die Locale-Datei zur Component gefunden werden kann, ist es erforderlich den Dateinamen
 * (ohne Dateiendung) in der Component-Klasse, in der Objekt-Variablen "$_localeFile", anzugeben.
 *
 * Beispiel:
 *
 *  <pre>
 *    <code>
 *       protected $_localeFile = 'user-form';
 *    </code>
 *  </pre>
 * In der gleichen Datei können auch die individuellen Fehlermeldungen definiert werden.
 *
 * Beim Aufbau der Schlüssel der individuellen Fehlermeldungen muss wieder das Präfix "form-error"
 * verwendet werden. Diesmal gefolgt vom internen Feldnamen und der Laravel Validation-Rule, jeweils
 * getrennt durch einen Punkt.
 *
 * Beispiele:
 *
 *  <pre>
 *    <code>
 *      'form-error.email.required'                 => 'Der Wert des Feldes ":attribute" ist eine Pflichtangabe.',
 *      'form-error.email.email'                    => 'Die angegebene E-Mail-Adresse hat ein ungültiges Format.',
 *      'form-error.organizationalunit_id.required' => 'Es wurde keine :attribute ausgewählt.',
 *    </code>
 *  </pre>
 *
 * @version     1.0.0 / 2025-05-25
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
trait ValidationTrait
{


/* +++ OBJECT MEMBERS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS MEMBERS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ OBJECT METHODS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


    /**
     * Liefert Fehlermeldungen zu den in der Klasse definierten Validation-Regeln
     *
     * Anstelle des internen Feldnamen wird das Label des Eingabedeldes in der Fehlermeldung verwendet.
     * Dazu muss die Locale für den Feldnamen folgendermaßen benannt sein: "label.#Field#"
     * Beispiel:
     *      'label.email' => 'E-Mail-Adresse'
     *
     * Zu jeder/jedem verwendeten Rule/Typ muss in der globalen Locale-Datei eine universelle
     * Fehlermeldung in der Form "form-error.#RuleType#" definiert sein, wobei #RuleType", für die/den
     * Rule/Typ steht (@see https://laravel.com/docs/9.x/validation#available-validation-rules).
     * Beispiel:
     *      'form-error.required' => 'Das Feld ":attribute" ist ein Pflichtfeld.'
     *
     * Zusätzlich kann auch eine spezifischere Fehlermeldung in der Locale-Datei der Komponente
     * definiert werden. Dazu muss die verwendende Klasse eine protected Eigenschaft $_localeFile
     * implementieren, die den Namen den Namen der zugehörigen Locale-Datei enthält.
     * Beispiel:
     *      protected $_localeFile = 'user-form';
     *
     * Die entsprechednen Locale-Definitionen könnten dann so aussehen:
     *      'form-error.email' => 'Die angegebene E-Mail-Adresse ist ungültig.',
     *      'form-error.required' => 'Es wurde keine E-Mail-Adresse eingegeben.',
     *
     * In den Fehlermeldungen kann auch der Platzhalter :attribute verwendet werden.
     *
     * Sollte es weder eine spezifische noch eine universelle Fehlermeldung geben, dann wird die
     * Standardfehlermeldung aus der Locale-Datei "validation.php" verwendet.
     *
     * Für die Durchführung der Validierung wird der folgende Code benötigt:
     *
     *      $this->withValidator(function (Validator $Validator)
     *      {
     *          $errors = $Validator->getMessageBag()->all();
     *
     *          if (!empty($errors)) {
     *              $this->_showNotification($errors);
     *          }
     *      })->validate();
     *
     *
     * @todo        - Bisher wurden nur globale Fehlermeldungen für einfache Prüfungen (required,
     *                number, integer) definiert und verwendet. Komplexere Rules (wie zum Beispiel
     *                "size:value" oder auch "email:rfc,dns") werden aktuell noch nicht behandelt,
     *                beziehungsweise die weiteren Parameter (nach ":") werden einfach verworfen.
     *
     * @return      array
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function messages()
    {
        $messages = array();

        foreach ($this->rules() as $attribute => $rules) {
            if (!is_array($rules)) {
                $rules = explode('|', $rules);
            }
            foreach ($rules as $rule) {
                $labels = array(
                    'attribute' => __($this->localeFile.'.label.'.$attribute)
                );
                /*
                **  In vielen Fällen kann eine Rule auch aus mehreren Teilen bestehen. Die einzelnen
                **  Teile (Regel und erweiterte Definition) sind durch einen Doppelpunkt (:)
                **  miteinander verbunden. */
                $ruleparts = explode(':', $rule);
                $rule = $ruleparts[0];

                if (isset($ruleparts[1])) {
                    /*
                    **  Für den Fall, dass eine erweiterte Definition vorhanden ist, wird hier
                    **  anhand der konkreten Rule eine Sonderbehandlung durchgeführt. */
                    switch ($ruleparts[0]) {
                        /*
                        **  Bei den nachfolgenden Regeln enthält die erweiterte Definition einen
                        **  zweiten Feldnamen, dessen Label ermittelt wird, um den Feldnamen in
                        **  der Fehlermeldung dadurch zu ersetzen. */
                        case 'different':
                        case 'in_array':
                        case 'same':
                            $labels['other'] = __($this->localeFile.'.label.'.$ruleparts[1]);
                            break;
                    }
                }
                /*
                **  Individuelle Fehlermeldung ermitteln. */
                $key = $this->localeFile.'.form-error.'.$attribute.'.'.$rule;

                $message = __($key, $labels);
                /*
                **  Die Methode __() liefert, für den Fall dass kein entsprechender Schlüssel
                **  gefunden werden konnte, den Schlüssel selbst zurück. Nur wenn die Rückgabe nicht
                **  dem Schlüssel entspricht, wird die Fehlermeldung an den Array angehängt. */
                if ($message !== $key) {
                    $messages[$attribute.'.'.$rule] = $message;

                    continue;
                }
                /*
                **  Globale Fehlermeldung ermitteln. */
                $key = 'global.form-error.'.$rule;

                $message = __($key, $labels);

                if ($message !== $key) {
                    $messages[$attribute.'.'.$rule] = $message;
                }
            }
        }
        return $messages;

    } // messages()


/* +++ CLASS METHODS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


} // trait ValidationTrait {}
