yakamara / yform

YForm für REDAXO 5 – Formulare im Frontend und Backend mit Verwaltung von Datenbank-Tabellen.
MIT License
77 stars 55 forks source link

EP YFORM_DATA_UPDATED enthält in $old_data nicht alte Daten, wenn per YOrm gespeichert #1443

Open alxndr-w opened 1 year ago

alxndr-w commented 1 year ago

https://github.com/yakamara/redaxo_yform/blob/1fad431332911e8921b3f3c213d382d2125247f1/plugins/manager/lib/yform/manager/dataset.php#L554

Ich habe einen EP, der wie folgt aufgebaut ist:

    public static function yform_ticket_mail($ep) :void
    {
        $subject = $ep->getSubject();
        $table = $subject->objparams['main_table'];

        if ($table == "rex_dance_event_ticket") {

            $old_status = $ep->getParams()['old_data']['status'];
            $new_status = $ep->getParams()['data']->getValue('status');

            $subject->getForm();

            if ($old_status !== $new_status && $new_status !== 0) {
                $yform = new rex_yform();
                $yform->setObjectparams('csrf_protection', false);
                $yform->setValueField('hidden', ['event_date_id',$ep->getParams()['data']->getValue('event_date_id'), null, true]);
                $yform->setValueField('hidden', ['event_name',$ep->getParams()['data']->getRelatedDataset('event_date_id')->getName(), null, true]);
                $yform->setValueField('hidden', ['event_date',$ep->getParams()['data']->getRelatedDataset('event_date_id')->intlDate('startDate'), null, true]);
                $yform->setValueField('hidden', ['name',$ep->getParams()['data']->getValue('name')]);
                $yform->setValueField('hidden', ['email',$ep->getParams()['data']->getValue('email')]);
                $yform->setValueField('hidden', ['number',$ep->getParams()['data']->getValue('number')]);
                $yform->setValueField('hidden', ['status',$ep->getParams()['data']->getValue('status')]);

                $email_templates = [
                    -1 => 'dance_event_ticket_cancelled',
                    1 => 'dance_event_ticket_confirmed'
                ];
                $yform->setActionField('tpl2email', [$email_templates[(int) $new_status], 'email']);
                $yform->setActionField('tpl2email', [$email_templates[(int) $new_status], 'info@example.org']);

                $yform->getForm();
                $yform->setObjectparams('send', 1);
                $yform->executeActions();
            }
        }

    }

Dieser wird grundsätzlich erfolgreich getriggert, wenn der Datensatz sich ändert - egal, ob über das Table Manager Backend, oder per YOrm-Aufruf, gelöst über eine rex_api.

Wie zu entnehmen ist, möchte ich, dass eine Mail versendet wird, wenn der Status sich von 0 auf nicht-0 ändert. Das klappt auch über den Table Manager. Ich erhalte in $old_status den bisherigen Wert und anschließend den neu gespeicherten.

Hingegen über das direkte Speichern mit YOrm erhalte ich reproduzierbar sowohl als alten, als auch als neuen Wert denselben.


<?php

class rex_api_dance_event_ticket extends rex_api_function
{
    protected $published = true;

    public function execute()
    {
        rex_response::cleanOutputBuffers();

        $api_key = rex_request('api_key', 'string', "");
        $status = rex_request('status', 'string', '0');

        $ticket = dance_event_ticket::query()->where('api_key', $api_key)->findOne();

        $old_status = $ticket->getValue('status');
        if ($ticket) {
            $ticket->setValue('status', $status);
            if (!$ticket->save()) { //
                rex_logger::factory()->log('Error', 'error: API Call: rex_api_dance_event_ticket status not saved');
                rex_response::setStatus(rex_response::HTTP_BAD_REQUEST);
            } else {
                    if($status == 1) {
                        echo "✅ bestätigt, Mail wurde versendet.";
                    } elseif($status == -1) {
                        echo "❌ storniert, Mail wurde versendet.";
                    } else {
                        echo "🤔 bereits bearbeitet? Keine Mail wurde versendet.";
                    }
                }

                rex_response::setStatus(rex_response::HTTP_OK);
            }
        } else {
            rex_logger::factory()->log('Error', 'error: API Parameter not correct');
            rex_response::setStatus(rex_response::HTTP_BAD_REQUEST);
        }
        exit();
    }
}

Ich speichere mit $ticket->save() das Ticket, der EP wird ordnungsgemäß aufgerufen.

michael-kreatif commented 1 year ago

Kanns leider auch reproduzieren und ist unangenehm, weil man den Fehler leider nicht sofort findet. Hatte das Problem auch schon ein paar Mal, sobald man auf Datenänderung in Yform reagieren möchte.

Also so wie bei Alex -> wenn im Redaxo Backend im YForm Formular gespeichert wird, dann enthält oldData die ursprünglichen Daten. Wenn aber direkt über YOrm gespeichert, dann enthält oldData immer die aktuellen Daten, da das selbe Objekt verwendet wird, wo man bereits die Values über setValue gesetzt hat.

Somit ist oldData bei direkter YOrm Speicherung aktuell sinnlos, weil man doch nicht abfragen kann, ob sich die Werte geändert haben oder nicht.

/* @var rex_yform_manager_dataset|null $modelClass / $modelClass = rex_yform_manager_dataset::get($data_id, $table); if ($modelClass) { $modelClass->setValue('status', (int) $status); $modelClass->save(); }

https://github.com/yakamara/redaxo_yform/blob/master/plugins/manager/lib/yform/manager/dataset.php#L517