Wie Helper Klasse manipulieren / hooken?

Hallo Community, ich möchte ein HelperClass in SearchBundleDBAL modifizieren. Am besten hooken und den Rückgabewert ändern. Ist das überhaupt möglich? Mein Versuch geht nicht. Welche Alternativen hätte ich? Bin Dankbar für jeden Vorschlag. public function install() { $this-\>subscribeEvent( //'Shopware\_Bundle\_SearchBundleDBAL\_PriceHelper::getSelection::after', 'Shopware\Bundle\SearchBundleDBAL\PriceHelper::getSelection::after', 'afterGetSelection' ); return true; } public function afterGetSelection(Enlight\_Hook\_HookArgs $arguments) { $temp = $arguments-\>getReturn(); // Debug ob\_start(); var\_dump($temp); $datei = fopen("./logs/ott.log","a+"); fwrite($datei, ob\_get\_contents() . "\n"); ob\_end\_clean(); $arguments-\>setReturn($temp); }

Hi, in den Bundles wird nicht mehr gehookt, stattdessen nutzen wir einen Decorator-Pattern, der euch für public-Methoden das gleiche erlaubt: https://developers.shopware.com/develop … xtensions/ Besten Gruß, Daniel

1 „Gefällt mir“

Ein Hinweis von meiner Seite - weil ich anfangs Probleme hatte den richtigen service zu finden: Unter /engine/Shopware/Bundle/SearchBundleDBAL/services.xml werden alle services dieses bundles registriert. Du suchst: <service id="shopware_searchdbal.search_price_helper_dbal" class="Shopware\Bundle\SearchBundleDBAL\PriceHelper"> <argument type="service" id="dbal_connection"></argument> <argument type="service" id="config"></argument> </service> Viele Grüße

danke für die Tips. Soweit sollte ich es versatanden haben: public function install() { $this-\>subscribeEvent( 'Enlight\_Bootstrap\_AfterInitResource\_shopware\_searchdbal.search\_price\_helper\_dbal', 'modPriceHelper', 500 ); return true; } public function afterInit() { $this-\>get('Loader')-\>registerNamespace('ShopwarePlugins\OttTestZwei', $this-\>Path()); } public function modPriceHelper() { $coreHelper = Shopware()-\>Container()-\>get('shopware\_searchdbal.search\_price\_helper\_dbal'); //$newHelper = new ModPriceHelper($coreHelper); $newHelper = $coreHelper; Shopware()-\>Container()-\>set('shopware\_searchdbal.search\_price\_helper\_dbal', $newHelper); Mir ist das mit dem ersetzen / ändern noch nicht ganz klar. Gibt es dazu noch ein weiteres Beispiel? Im Prinzip will ich genau diesen Funktion ändern. https://github.com/shopware/shopware/bl … er.php#L66 Vielen Dank euch.

hier mal mein versuch. OttTestZwei\Bootstrap.php [code]<?php use ShopwarePlugins\OttTestZwei\SearchBundleDBAL\ModPriceHelper;

class Shopware_Plugins_Frontend_OttTestZwei_Bootstrap extends Shopware_Components_Plugin_Bootstrap
{

public function install()
{

    $this->subscribeEvent( 'Enlight\_Bootstrap\_AfterInitResource\_shopware\_searchdbal.search\_price\_helper\_dbal', 'modPriceHelper', 500 ); return true; } public function afterInit() { $this-\>get('Loader')-\>registerNamespace('ShopwarePlugins\OttTestZwei', $this-\>Path()); } public function modPriceHelper() { $coreHelper = Shopware()-\>Container()-\>get('shopware\_searchdbal.search\_price\_helper\_dbal'); $newHelper = new ModPriceHelper($coreHelper, NULL); Shopware()-\>Container()-\>set('shopware\_searchdbal.search\_price\_helper\_dbal', $newHelper); } [/code] OttTestZwei\SearchBundleDBAL\ModPriceHelper.php [code]<?php namespace Shopware\Bundle\SearchBundleDBAL;

use Shopware\Bundle\StoreFrontBundle\Struct;

class ModPriceHelper implements PriceHelperInterface
{

/**
 * @var Connection
 */
private $connection;
/**
 * @var \Shopware_Components_Config
 */
private $config;
/**
 * @param Connection $connection
 * @param \Shopware_Components_Config $config
 */
public function __construct(Connection $connection, \Shopware_Components_Config $config)
{
    $this->connection = $connection; $this-\>config = $config; } /\*\* \* @inheritdoc \*/ public function getSelection(Struct\ShopContextInterface $context) { $fallback = $context-\>getFallbackCustomerGroup(); $current = $context-\>getCurrentCustomerGroup(); $currency = $context-\>getCurrency(); $priceField = 'defaultPrice.price'; if ($fallback-\>getId() != $current-\>getId()) { $priceField = 'IFNULL(customerPrice.price, defaultPrice.price)'; } $discount = $current-\>useDiscount() ? $current-\>getPercentageDiscount() : 0; $considerMinPurchase = $this-\>config-\>get('calculateCheapestPriceWithMinPurchase'); //rounded to filter this value correctly // =\> 2,99999999 displayed as 3,- € but won't be displayed with a filter on price \>= 3,- € return 'ROUND(' . //customer group price (with fallback switch) $priceField . //multiplied with the variant min purchase ($considerMinPurchase ? ' \* availableVariant.minpurchase' : '') . //multiplied with the percentage price group discount ' \* ((100 - IFNULL(priceGroup.discount, 0)) / 100)' . //multiplied with the product tax if the current customer group should see gross prices ($current-\>displayGrossPrices() ? " \* ((tax.tax + 100) / 100)" : '') . //multiplied with the percentage discount of the current customer group ($discount ? " \* " . (100 - (float) $discount) / 100 : '') . //multiplied with the shop currency factor ($currency-\>getFactor() ? " \* " . $currency-\>getFactor() : '') . ', 2)'; } /\*\* \* @inheritdoc \*/ public function joinPrices( QueryBuilder $query, Struct\ShopContextInterface $context ) { if ($query-\>hasState(self::STATE\_INCLUDES\_CHEAPEST\_PRICE)) { return; } $this-\>joinDefaultPrices($query, $context); $graduation = 'customerPrice.from = 1'; if ($this-\>config-\>get('useLastGraduationForCheapestPrice')) { $graduation = "customerPrice.to = 'beliebig'"; } $query-\>leftJoin( 'product', 's\_articles\_prices', 'customerPrice', 'customerPrice.articleID = product.id AND customerPrice.pricegroup = :currentCustomerGroup AND ' . $graduation . ' AND availableVariant.id = customerPrice.articledetailsID' ); $query-\>leftJoin( 'product', 's\_core\_pricegroups\_discounts', 'priceGroup', 'priceGroup.groupID = product.pricegroupID AND priceGroup.discountstart = 1 AND priceGroup.customergroupID = :priceGroupCustomerGroup AND product.pricegroupActive = 1' ); $query-\>setParameter(':currentCustomerGroup', $context-\>getCurrentCustomerGroup()-\>getKey()) -\>setParameter(':priceGroupCustomerGroup', $context-\>getCurrentCustomerGroup()-\>getId()); $query-\>addState(self::STATE\_INCLUDES\_CHEAPEST\_PRICE); } /\*\* \* @inheritdoc \*/ public function joinDefaultPrices(QueryBuilder $query, Struct\ShopContextInterface $context) { if ($query-\>hasState(self::STATE\_INCLUDES\_DEFAULT\_PRICE)) { return; } $this-\>joinAvailableVariant($query); $graduation = 'defaultPrice.from = 1'; if ($this-\>config-\>get('useLastGraduationForCheapestPrice')) { $graduation = "defaultPrice.to = 'beliebig'"; } $query-\>innerJoin( 'product', 's\_articles\_prices', 'defaultPrice', 'defaultPrice.articledetailsID = availableVariant.id AND defaultPrice.pricegroup = :fallbackCustomerGroup AND ' . $graduation ); $query-\>setParameter( ':fallbackCustomerGroup', $context-\>getFallbackCustomerGroup()-\>getKey() ); $query-\>addState(self::STATE\_INCLUDES\_DEFAULT\_PRICE); } /\*\* \* @inheritdoc \*/ public function joinAvailableVariant(QueryBuilder $query) { if ($query-\>hasState(self::STATE\_INCLUDES\_AVAILABLE\_VARIANT)) { return; } $stockCondition = ''; if ($this-\>config-\>get('hideNoInstock')) { $stockCondition = 'AND (product.laststock \* availableVariant.instock) \>= (product.laststock \* availableVariant.minpurchase)'; } $query-\>innerJoin( 'product', 's\_articles\_details', 'availableVariant', 'availableVariant.articleID = product.id AND availableVariant.active = 1 ' . $stockCondition ); $query-\>addState(self::STATE\_INCLUDES\_AVAILABLE\_VARIANT); } } [/code] Fehler: Fatal error: Class 'ShopwarePlugins\OttTestZwei\SearchBundleDBAL\ModPriceHelper' not found in /var/www/clients/client1/web8/web/engine/Shopware/Plugins/Local/Frontend/OttTestZwei/Bootstrap.php on line 31 503 Service Unavailable Ich hoffe der Ansatz stimmt.

Ohne deinen code weiter analysiert zu haben: deine namespaces sind falsch. Ein Beispiel: subscriber: http://pastebin.com/tYLZrCtd list product service: http://pastebin.com/pnfUn0mn plugin service: http://pastebin.com/VKkr5rAt Viele Grüße

1 „Gefällt mir“

Danke, ich habe es nun mit eurer Hilfe hinbekommen. Eine Frage habe ich aber noch. Ich möchte nur eine Funktion anpassen. https://github.com/shopware/shopware/bl … er.php#L66 Muss ich dann trotzdem alle anderen Funktionen auch in meiner eigenen Klasse angeben? Wenn ich es nicht machte kommt ein Fehler. Ich habe die nun einfach vom Original rein kopiert. Geht erst mal. Wie ist es wenn es mehrere Plugins gibt, die hier an der Stelle Änderungen vornehmen? Überschreiben die sich dann gegenseitig? Nur Informativ. Danke

[quote=„ottscho“] Muss ich dann trotzdem alle anderen Funktionen auch in meiner eigenen Klasse angeben? Wenn ich es nicht machte kommt ein Fehler. Ich habe die nun einfach vom Original rein kopiert. Geht erst mal. [/quote] Kannst du nicht von der Original-Klasse erben? Also in der Art: class ModPriceHelper extends PriceHelper implements PriceHelperInterface Grüße, Sven

doch, geht. Danke.

Du musst dann nur aufpassen, falls andere Plugins die gleiche Klasse dekorieren. Viele Grüße

Hi, das Erben und „reinkopieren“ von Code ist beides tödlich für die Erweiterbarkeit. In beiden Fällen bindest du dich hart an die Implementierung der Shopware-Original-Klasse. Wenn ein anderes Plugin (vor dir) die Klasse dekoriert, deaktivierst du dessen Erweiterbarkeit damit de facto. Die einzige (richtige) Möglichkeit ist es, sich den Original-Service in seinen Service zu injecten und den dann ggf. intern aufzurufen. Beispiel hängt an, bitte nur diesen Weg gehen. Gruß, Daniel

D.h., wenn ich es korrekt verstehe, ich manipuliere nicht den Code der Funktion, sondern fange den Rückgabewert der Funktion ab, und passe diesen an? $result = $this-\>decorated-\>getList($numbers, $context); //Hier den Inhalt manipulieren -\> $result return $result; So wie ein Hook After?

Hi, ja, genau. So kannst du quasi before / after und replace-Hooks haben, ohne wirklich Hooks zu haben :slight_smile: Replace (also gar nicht die Original-Methode aufrufen) ist aber weiterhin böse :slight_smile: Schönen Abend! Daniel

@Daniel Nögel schrieb:

Hi,

das Erben und „reinkopieren“ von Code ist beides tödlich für die Erweiterbarkeit. In beiden Fällen bindest du dich hart an die Implementierung der Shopware-Original-Klasse. Wenn ein anderes Plugin (vor dir) die Klasse dekoriert, deaktivierst du dessen Erweiterbarkeit damit de facto.

Die einzige (richtige) Möglichkeit ist es, sich den Original-Service in seinen Service zu injecten und den dann ggf. intern aufzurufen.

Beispiel hängt an, bitte nur diesen Weg gehen.

 

Hi,

gibt es das Beispiel, um nur eine Funktion der Helperklasse auszutauschen noch?

LG