Hallo, ich glaube ich habe das Konzept mit den neuen Services noch nicht ganz verstanden. Das diese wesentlich einfacher austauschen sind, als vorher habe ich verstanden, vorausgesetzt man tauscht den ganzen Service aus. Wie ist denn jetzt die Best Pratice um kleine Änderungen vorzunehmen? Ein aktuelles Beispiel: Ich hätte gerne ein Produkt, dass nur über einen Direktlink aufgerufen werden kann. Es soll also in keiner Kategorie und auch nicht in der Suche auftauchen. Also Artikel aktiviert und keiner Kategorie zugewiesen => Die Detailseite des Artikels scheitert am Aufruf von ProductNumberService->isProductAvailableInShop(). Eigentlich wäre mein Ansatz, vom Service zu erben und diese Methode zu überschreiben. Funktioniert aber nicht, da die Methode private ist. ProductNumberService->getAvailableNumber() wäre public, um diese zu überschreiben muss ich aber die privaten Methoden getProductIdByNumber, isProductAvailableInShop, getNumberBySelection, isNumberAvailable und findFallbackById ebenfalls implentieren. Also kopiere ich 50% des ProductNumberService in meinenProductNumberService und passe die Methode an. Bei jedem Update darf ich dann, überprüfen ob sich etwas am von mir kopierten und nicht modifizierten Code geändert hat… Da muss es doch einen besseren Weg geben, oder? Dirk
Wenn es keinen besseren Weg gibt. Wäre es dann nicht sinnvoll die privaten Methoden aus den Services als “Protected” zu definieren?
Ich stand zwar noch nie vor dem Problem - aber das würde mich auch mal interessieren. Viele Grüße
Ich stand kürzlich an anderer Stelle vor der gleichen Problematik - und habe auch zähneknirschend Code kopiert, im festen Bewusstsein, dass ich wahrscheinlich im entscheidenden Moment vergesse, nach Änderungen an der ursprünglichen Codebasis zu schauen. „protected“ löst das Problem imho nicht wirklich. Klar, zunächst würde man sich die Arbeit sparen, den Code zu kopieren. Aber du kannst dich nicht darauf verlassen, dass die Methode nach einem Update noch existiert, oder die API noch identisch ist, oder sie immer noch (nur) dem gewünschten Zweck dient. Also müsstest du doch jedes Mal schauen, ob der Code noch so ist, wie du ihn erwartest. Meines Erachtens wäre die Lösung, den Code in viele kleine Methoden aufzusplitten, die dann „public“ sind und im Interface des Service aufgeführt sind (bzw. mehr Services aufzuführen). Bevor die Methode dann verschwindet, wird sie erst auf „deprecated“ gesetzt und man hat Zeit, sich auf die Änderung einzustellen.
Alles auf public zu stellen wäre zwar für uns Pluginentwickler praktisch, würde aber ein Refactoring auf Seiten von Shopware unnötig in die länge ziehen. Mit protected müsste man zwar trotzdem reagieren, falls Shopware etwas gravierend ändert. Wenn aber nur Security- oder Bugfixes gemacht werden, würden diese automatisch übernommen werden.
In einem System, das dich für Erweiterungen dazu ermutigt, von den system-eigenen Klassen zu erben, bringt ein “protected” imho für Shopware ebenfalls die Verantwortung mit sich, Änderungen an der API/Funktionsweise anzukündigen. Denn sie geben die Methode ja an den Plugin-Entwickler raus, der sich auf sie verlässt. Somit ist das Refactoring eh erschwert. Der Unterschied zu “public” ist in dem Fall lediglich, dass PHP dies nicht formal über Interfaces darstellen kann. Ich sage ja auch nicht, dass einfach alles auf “public” gestellt werden soll, was jetzt “private” ist. Eine “public”-Methode wie “isProductAvailableInShop” würde imho eh besser in einen anderen Service passen (denn was hat das mit Produktnummern zu tun?). Und warum sollte man sie dort nicht öffentlich zur Verfügung stellen? Zu deinem konkreten Beispiel: Du könntest in deinem abgeleiteten Service einfach die getAvailableNumber-Methode von parent aufrufen. Falls dabei die RuntimeException(“Product not available in current shop”) geworfen wird, prüfst du, ob dein Produkt nicht doch angezeigt werden soll.