Kundenänderungen beobachten / speichern

Hallo,

ich arbeite aktuell an einem Plugin, das Änderungen an Kundendatensätzen speichert und per Cron per E-Mail verschickt.

Dazu habe ich ein Doctrine-Subscriber erstellt der auf das onFlush achtet.

public function onFlush(OnFlushEventArgs $args)
{
  $em = $args->getEntityManager();
  $uow = $em->getUnitOfWork();

  foreach ($uow->getScheduledEntityUpdates() as $keyEntity => $entity)
  {
    if ($entity instanceof Customer)
    {
      foreach ($uow->getEntityChangeSet($entity) as $keyField => $field) {
        ...
      }
    }
  }
}

Nur erhalte ich alle Änderungen die mit einem Flush in die Datenbank geschrieben werden.

$field ist ein Array mit zwei Werte. Dem alten und dem neuen.

Mein Problem ist, dass ich jedesmal die Kundengruppe erhalte obwohl sich nichts geändert hat.

Man könnte jetzt $field[0] mit $field[1] vergleichen, allerdings ist in $field[0] nicht die Customer-Group sondern ein Proxy von Doctrine (Shopware\Proxies__CG__\Shopware\Models\Customer\Group).

Das Proxy ist de facto leer. Wenn ich mit getId() versuche an die Gruppen-ID zu kommen, erhalte ich null.

Ich habe versucht am Proxy selber per __load() ein Laden der Daten anzustoßen, aber das funktioniert ebenfalls nicht.

Ich komme nicht an die alte Gruppe. Wenn ich nicht im onFlush sondern im preUpdate arbeite, erhalte ich trotzdem die neue Kundengruppe.

Bei anderen Properties wie firstname, lastname sind die alten und neuen Werte als String in field enthalten.

Hatte schon jemand ein ähnliches Problem und konnte dies lösen?

 

Vielleicht ein falscher Ansatz. Ein ähnliches Projekt haben wir (in der Firma) bei einem Kunden umgesetzt. Hier wird aber die Änderung zur Laufzeit versendet - also dann, wenn der Kunde auch wirklich seine Daten ändert. Eventuell ist das ja eine Alternative zum Cronjob.

@R4M schrieb:

Vielleicht ein falscher Ansatz. Ein ähnliches Projekt haben wir (in der Firma) bei einem Kunden umgesetzt. Hier wird aber die Änderung zur Laufzeit versendet - also dann, wenn der Kunde auch wirklich seine Daten ändert. Eventuell ist das ja eine Alternative zum Cronjob.

Danke für die Antwort, aber die Änderung soll direkt zur Laufzeit notiert werden, bzw. das onFlush wird aufgerufen, wenn Datensätze in die Datenbank geschrieben werden.

Ich möchte mir dann die Änderungen in einer eigenen Tabelle notieren und irgendwann per CRON (Kundenwunsch) verschicken.

Das Problem ist auch eigentlich nur die Kundengruppe, die man irgendwie immer im changeset hat, egal ob sie geändert wurde oder nicht und in field[0] immer ein leeres Doctrine-Proxy hat.

Sollte man dazu nicht einfach den AddressService dekorieren?

@BestShopPossible schrieb:

Sollte man dazu nicht einfach den AddressService dekorieren?

Ich habe versucht den AddressService zu dekorieren, allerdings erhalte ich die Änderungen nicht. im Update wird nur die neue Adresse aufgelistet:

**public function** update(Address $address)

In der Datenbank ist der neue Wert schon gespeichert.

Hä?

  1. AddressService dekorieren

  2. in

    public function update (Address address) {
    //address ist die neue Adresse

     $oldAdress = $this->getAddressFromDBAndMakeItComparable($address->getId());
    
     if($oldAdress != address) {
         $this->setDirtyFlagOnCustomerOrAddress($addressIDOrCustomerID);
     }
    
     $this->coreAddressService->update(address);
    

    }

Wo gibt es dort ein Problem? Versteh ich nicht…

 Die alten Daten entsprechen den neuen Daten. Wenn ich mir den Vor- und Nachnamen speichere und die Daten bei einer Adresse im Backend ändere erhalte ich die gleichen Daten. **public function** update(Address $address) {$address2 = Shopware()-\>Models()-\>find(Address::_class_, $address-\>getId()); file\_put\_contents('address.txt', $address2-\>getFirstname().' - '.$address2-\>getLastname()." --\>\n",_FILE\_APPEND_); file\_put\_contents('address.txt', $address-\>getFirstname().' - '.$address-\>getLastname()." --\>\n",_FILE\_APPEND_); $this-\>addressService-\>update($address); }

Inhalt von address.txt ->

Teddy - Tester  -->
Teddy - Tester  -->

 

Na ist ja klar das da schon die neuen Daten drinstehen. 

Deswegen habe ich die Funktion ja auch

getAddressFromDB AndMakeItComparable

genannt.

 

$address2 kommt aus der Datenbank.

Ich wüsste nicht wo ich die alten Daten sonst herbekomme.

 $address2 kommt aus der Datenbank.

Nein.

Dort stehen die alten Daten: 

$sql = "SELECT * FROM s_user_addresses WHERE id = :id";
$dbData = Shopware()->fetchRow($sql, array(':id' => $address->getID());

Edit: Shopware()->Db()->fetch…

Edit2: ungetesteter Code

Ich hätte gedacht, dass

 $address2 = Shopware()-\>Models()-\>find(Address::_class_, $address-\>getId());

den Adressdatensatz aus der Datenbank liest, aber anscheinend gibt er die noch nicht gespeicherte Entität zurück, o.ä. Wahrscheinlich die Daten die mit der UnitOfWork für das Update eingereiht wurden.

 $sql = "SELECT \* FROM s\_user\_addresses WHERE id = :id"; $address3 = Shopware()-\>Models()-\>getConnection()-\>fetchAssoc($sql, **array** (':id' =\> $address-\>getId()));

Diese Abfrage liefert mir tatsächlich den Eintrag aus der Datenbank.

 

Ich kann nach dem find natürlich noch ein

 Shopware()-\>Models()-\>refresh($address2);

aufrufen, dann wird $address2 mit dem aktuellen Datenbankinhalt gefüllt, zerstört aber die Daten für das update.

 

Das direkte fetch hilft mir aber schon weiter, Danke.