[GELÖST] Shopware 5.2.0 - Eigener Controller & Model mit single_selection

Hallo liebe shopware - Gemeinde,

beim Versuch, ein Plugin mit einem Freitextfeld in Form eines Auswahlfeldes (inklusive eigenem Model etc) kompatibel mit Shopware 5.2.0 zu machen, komme ich nicht weiter. Der vorhandene Code ist (von Shopware selbst) dieser hier: Backend Components - Basics . Das Plugin klappte bis Shopware Version 5.1.6 natürlich problemlos.

Unter Shopware 5.2.0 erzeugt man ja ein Auswahlfeld durch single_selection : Attribute system . Nur sieht ja jetzt aber das updateSchema und vorallem das Model eines Plugins, was nur ab Shopware Version 5.2.0 funktionieren soll, völlig anders aus.

Der Code von Shopware bis 5.1.6 des updateSchema:

protected function updateSchema(){
     $this->registerCustomModels();
	 
     $em = $this->Application()->Models();
				
     $tool = new \Doctrine\ORM\Tools\SchemaTool($em);
		 
     $classes = array(
          $em->getClassMetadata('Shopware\CustomModels\Mymodel\Mymodel')
     );
		 
     try {
          $tool->dropSchema($classes);
     } catch (Exception $e) {

     }
				
     $tool->createSchema($classes);
}

Der Code von Shopware bis 5.1.6 des Models:

namespace Shopware\CustomModels\Mymodel;

use Shopware\Components\Model\ModelEntity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="s_core_mymodel")
 */
class Mymodel extends ModelEntity{
	/**
	 * @var integer $id
	 *
	 * @ORM\Id
	 * @ORM\Column(type="integer")
	 * @ORM\GeneratedValue(strategy="IDENTITY")
	 */
	private $id;

	/**
	 * @var string $storagelocation
	 *
	* @ORM\Column(type="text", nullable=true)
	 */
	private $name;
			
	/**
	 * @return int
	 */
	public function getId(){
		return $this->id;
	}

	/**
	 * @param string $storagelocation
	 */
	public function setName($name){
		$this->name= $name;
	}

	/**
	 * @return string
	 */
	public function getName(){
		return $this->name;
	}
}

Ich habe vorerst probiert, das updateSchema als auch das Model so zu belassen (da es ja auch abwärtskompatibel sein soll) und das Freitextfeld folgendermaßen zu erzeugen:

$service = $this->get('shopware_attribute.crud_service');
$service->update(
     's_articles_attributes',
     'attr_text',
     'single_selection',
     [
          'label' => 'MyText',
          'supportText' => '',
          'translatable' => false,
          'displayInBackend' => true,
          'position' => 1,
          'custom' => false,
          'entity' => \Shopware\CustomModels\Mymodel\Mymodel
     ],
     null,
     true
);

Leider wird mir nun kein einziger Wert im Auswahlfeld des Freitextfeldes angezeigt (es sind im Model aber natürlich genug Werte enthalten, das Auswahlfeld hat ja vorher auch funktioniert). Ich schätze mal, dass das entity nicht passt - ich habe da auch schon ein paar andere Möglichkeiten getestet, leider funktioniert keine.

 

Das updateSchema unter Shopware 5.2.0 sieht ja nun folgendermaßen aus:

$service = $this->container->get('shopware_attribute.crud_service');

//generates the database schema for the own entity SwagAttribute
$em = $this->container->get('models');
$schemaTool = new SchemaTool($em);
$schemaTool->updateSchema(
     [$em->getClassMetadata(\SwagAttribute\Models\SwagAttribute::class)],
     true
);

$service->update(
     's_articles_attributes',
     'my_multi_selection',
     'multi_selection',
     [
          'entity' => \SwagAttribute\Models\SwagAttribute::class,
          'displayInBackend' => true,
          'label' => 'My multi selection',
     ],
     null,
     true
);

Das Model unter Shopware 5.2.0 sieht ja nun folgendermaßen aus:

namespace SwagAttribute\Models;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="s_test")
 * @ORM\Entity
 */
class SwagAttribute
{
    /**
     * @var integer $id
     *
     * @ORM\Column(type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string $name
     *
     * @ORM\Column(type="string", length=500, nullable=false)
     */
    private $name;


    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }
}

Hat einer einen Tipp für mich, wie das entity aussehen müsste?

Beste Grüße

Sebastian

Hi Sebastian,

schreibst du dein Plugin auf das neue System um? (wegen des Namespace & AttributeBundle)

Wenn ja, wirst du sowieso 2 verschiedene Plugin Versionen maintainen müssen - eins das kompatibel bis Version 5.1.x ist und eins das kompatibel ab Version 5.2.x ist

LG, Jan

@Jan Bücker schrieb:

Hi Sebastian,

schreibst du dein Plugin auf das neue System um? (wegen des Namespace & AttributeBundle)

Wenn ja, wirst du sowieso 2 verschiedene Plugin Versionen maintainen müssen - eins das kompatibel bis Version 5.1.x ist und eins das kompatibel ab Version 5.2.x ist

LG, Jan

Hallo Jan,

nein ich schreibe es nicht um, ich behalte das alte bei und mache dies nur kompatibel mit Shopware Version 5.2.0 und entwickle dies dann weiter. Den Shopware Attribute Crud Service kann man ja auch so integrieren - Hauptsache man prüft eben bei den (neuen) Funktionen immer davor, ob Minimum Version 5.2.0 ( if ($this->assertMinimumVersion(‘5.2’)) {}) ) eingesetzt wird, und baut für die alten Varianten dann eben einen entsprechenden else - Zweig.

Ein komplett neues Plugin auf der neuen Shopware 5.2.0 Basis zu erstellen wäre ja auch ansich nicht im Sinne des Kunden - er müsste dann ja das neue Plugin extra kaufen und alle Einstellungen neu vornehmen / übertragen.

Um ein “Aufteilen der Versionen” auf die Kompatibilität zu Shopware 5.2 wird man wahrscheinlich dann aber früher oder später nicht drum herum kommen.

Beste Grüße

Sebastian

Hallo [@Jan Bücker](http://forum.shopware.com/profile/21387/Jan Bücker “Jan Bücker”)‍ ,

ich würde das Thema gern noch einmal aufgreifen.

Mein Model sieht folgendermaßen (nach den Shopware Vorgaben bis Shopware Version 5.1.6) aus:

namespace Shopware\CustomModels\Mymodel;

use Shopware\Components\Model\ModelEntity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="s_core_mymodel")
 */
class Mymodel extends ModelEntity{
	/**
	 * @var integer $id
	 *
	 * @ORM\Id
	 * @ORM\Column(type="integer")
	 * @ORM\GeneratedValue(strategy="IDENTITY")
	 */
	private $id;

	/**
	 * @var string $storagelocation
	 *
	* @ORM\Column(type="text", nullable=true)
	 */
	private $name;
			
	/**
	 * @return int
	 */
	public function getId(){
		return $this->id;
	}

	/**
	 * @param string $storagelocation
	 */
	public function setName($name){
		$this->name= $name;
	}

	/**
	 * @return string
	 */
	public function getName(){
		return $this->name;
	}
}

Die dazugehörige updateShema:

protected function updateSchema(){
     $this->registerCustomModels();
	 
     $em = $this->Application()->Models();
				
     $tool = new \Doctrine\ORM\Tools\SchemaTool($em);
		 
     $classes = array(
          $em->getClassMetadata('Shopware\CustomModels\Mymodel\Mymodel')
     );
		 
     try {
          $tool->dropSchema($classes);
     } catch (Exception $e) {

     }
				
     $tool->createSchema($classes);
}

Ich würde dies nun gern Shopware ab Version 5.2 kompatibel machen wollen - und würde dazu single_selection nutzen. Leider wird mir unter 5.2.1 kein einziger Wert angezeigt, obwohl ausreichend vorhanden sind.

Hast du für mich vielleicht einen Ansatz, wie ich die Kompatibilität herstellen könnte? Dies war ja schließlich bis 5.1.6 genau der Weg, den man gehen sollte.

Beste Grüße

Sebastian

Hallo @sschreier‍ ,

hast du dafür schon eine Lösung gefunden?
Ich hänge an der selben Stelle. Wenn ich ein Shopware Model bei ‘entity’ eintrage, erhalte ich alle Datensätze. Sobald ich mein eigenes Model (das im selben Plugin, an anderen Stellen einwandfrei funktioniert) erhalte ich keine Daten mehr.

 

Grüße

@MissTerious schrieb:

Hallo @sschreier‍ ,

hast du dafür schon eine Lösung gefunden?
Ich hänge an der selben Stelle. Wenn ich ein Shopware Model bei ‘entity’ eintrage, erhalte ich alle Datensätze. Sobald ich mein eigenes Model (das im selben Plugin, an anderen Stellen einwandfrei funktioniert) erhalte ich keine Daten mehr.

 

Grüße

Hallo,

leider nein - Shopware selbst hält sich bei diesem Thema ja auch eher bedeckt und gibt kein Beispiel oder Ansätze zur Lösung.

Beste Grüße

Sebastian

Hallo Sebastian,

danke für die schnelle Antwort! :slight_smile:

Ja es lässt sich absolut nichts dazu finden und jetzt bin ich auch selbst mit meinem Latein am Ende.

Ich kenne mich mit ExtJS nicht so gut aus, aber eine Idee wäre noch gewesen darüber irgendwie die gewünschten Daten zu ziehen/einzuspielen. Ob das überhaupt möglich ist, weiß ich nicht. In diese Richtung werde ich als nächstes Recherchieren und hoffe so auf ein Ergebnis zu stoßen.

Schönen Abend noch  und Grüße

Hi,

in dem obigen Source Code hast du den Namespace „namespace SwagAttributeTest\Models“ verwendet, dieser Funktioniert nur wenn du das neue Plugin System verwendest (welcher dann auch beim Kernel Boot automatisch registriert wird) oder wenn du diesen selbst in deinem Plugin manuel registriert hast. 

Der Fehler lag darin dass im alten Plugin System im Backend dein Model nicht automatisch registriert war, was in der Netzwerk Console ausgeben wird:

 

Anbei die Sourcen wie es funktioniert.

Bootstrap.php

updateSchema();

        $service = $this->get('shopware_attribute.crud_service');
        $service->update(
            's_articles_attributes',
            'attr_text',
            'single_selection',
            [
                'label' => 'MyText',
                'supportText' => '',
                'translatable' => false,
                'displayInBackend' => true,
                'position' => 1,
                'custom' => false,
                'entity' => \Shopware\CustomModels\MyModel\MyModel::class
            ],
            null,
            true
        );

        $this->subscribeEvent('Enlight_Controller_Action_PreDispatch_Backend_EntitySearch', 'registerSearch');

        return true;
    }

    public function registerSearch(Enlight_Event_EventArgs $args)
    {
        $this->registerCustomModels();
    }

    public function afterInit()
    {
        parent::afterInit();
        $this->registerCustomModels();
    }


    protected function updateSchema(){
        $this->registerCustomModels();

        $em = $this->Application()->Models();

        $tool = new \Doctrine\ORM\Tools\SchemaTool($em);

        $classes = array(
            $em->getClassMetadata('Shopware\CustomModels\Mymodel\Mymodel')
        );

        try {
            $tool->dropSchema($classes);
        } catch (Exception $e) {

        }

        $tool->createSchema($classes);
    }
}

 

Model:

id;
    }

    /**
     * @param string $storagelocation
     */
    public function setName($name){
        $this->name= $name;
    }

    /**
     * @return string
     */
    public function getName(){
        return $this->name;
    }
}

 

Ordner Struktur:

Bitte auf Groß und Kleinschreibung bei den Klassen achten sonst kommt der AutoLoader nicht zurecht.

Hoffe das hilft euch weiter

Gruß Oliver

 

1 Like

Hallo [@Oliver Skroblin](http://forum.shopware.com/profile/1871/Oliver Skroblin “Oliver Skroblin”)‍ ,

vielen Dank!

Jetzt funktioniert es einwandfrei.

Mit haben folgende 2 Funktionen gefehlt…

public function registerSearch(Enlight_Event_EventArgs $args)
    {
        $this->registerCustomModels();
    }

    public function afterInit()
    {
        parent::afterInit();
        $this->registerCustomModels();
    }

Liebe Grüße

Hallo [@Oliver Skroblin](http://forum.shopware.com/profile/1871/Oliver Skroblin „Oliver Skroblin“)‍ ,

vielleicht weißt du hier auch Rat:

Ich möchte nun auf die erstellte Attribut Spalte einen Foreign Key zu meinem Model(Tabelle) erstellen.

Über die Angabe in meinem Model

/**
     * INVERSE SIDE
     *
     * @var ArrayCollection
     *
     * @ORM\OneToMany(
     * targetEntity="Shopware\Models\Attribute\ArticleSupplier",
     * mappedBy="myAttribute"
     * )
     */
    protected $supplier;

komme ich nicht weiter. An das Attribut Model komme/sollte ich nicht ran und über die crud_service update Funktion kann ich das auch nicht steuern, richtig?

Wie geht man hier vor?

 

Grüße

MissTerious

Habe noch nicht ganz verstanden was du erreichen willst.

Du würdest gerne definieren:

„MyModel hat eine 1:N Beziehung zu dem HerstellerAttributeModel. Und in dem Hersteller Attribute Model gibt es eine spalte my_model_id welche als Join Bedingung für diese assoziation gelten soll“?

Wenn das der Fall ist (noch selbst nicht probiert), probier mal in MyModel.php folgendes aus:

 

/**
 * @var ArrayCollection
 *
 * @ORM\OneToMany(
 * targetEntity="Shopware\Models\Attribute\ArticleSupplier"
 * )
 * @ORM\JoinColumn(name="id", referencedColumnName="my_model_id")
 */
protected $suppliers;

 

Hallo [@Oliver Skroblin](http://forum.shopware.com/profile/1871/Oliver Skroblin “Oliver Skroblin”)‍ ,

das funktioniert leider nicht.

Habe dir hier mal ein grobes Datenbankmodell erstellt:

Ich habe mit dem Crud Service wie oben meine Spalte s_articles_supplier_attributes.my_table_id erstellt.

Zuvor hatte ich eine dazu passende Tabelle (my_table) mit Id usw. erstellt. Dazu gibt es ein Model, das ich beim Crud Service über das ‘entity’ eingebunden habe und somit werden nun alle Daten aus diesem Model einwandfrei im Backend in dem Attributsfeld (single_selection) geladen.

Bei s_articles_supplier_attributes.supplierID gibt es einen Foreign Key (roter Pfeil) auf s_articles_supplier.ID. Wenn der Supplier gelöscht wird, löscht sich auch der passende Datensatz in der DB.

Ich möchte nun:

Einen solchen Foreign Key (dicker roter Pfeil) bei my_table.id auf s_articles_supplier_attributes.my_table_id. Ich kann ja nur auf meinem Model (my_table) arbeiten und nicht an der Attribut-Tabelle. Deshalb kann ich eine Assoziation nur einseitig eintragen, wo entweder Shopware bei Installation des Plugins meckert oder einfach nichts passiert.

Effekt soll folgender sein : Wenn ich einen Datensatz in my_table lösche, muss der passende Datensatz in s_articles_supplier_attributes in der Spalte my_table_id auf NULL gesetzt werden. (muss)

Schön wäre außerdem : Dass die Models die Beziehungen kennen. D.h. dass wenn ich einen Supplier über Doctrine lade dann auch alle Attribute und Daten aus my_table zur Verfügung stehen. In diesem Fall wäre bei Plugininstallation ein Plain SQL setzen des Keys sinnfrei.

 

Ob generell Probleme im Nachhinein auftreten wenn ich bei Plugininstallation den Foreign Key über Plain SQL setzte, kann ich nicht abschätzen. Da wären wir aber nicht mehr am Shopware Standart, also sowieso nicht toll. Beste Lösung wäre eigentlich wenn hier beim Spaltenanlegen über den Crud Service solche Optionen wie “Foreign Key auf… setzen” gegeben wären. Konnte ich so aber nicht finden.

 

Ich wünsche ein schönes Wochenende.

Grüße,

MissTerious

@Oliver Skroblin schrieb:

Hi,

in dem obigen Source Code hast du den Namespace „namespace SwagAttributeTest\Models“ verwendet, dieser Funktioniert nur wenn du das neue Plugin System verwendest (welcher dann auch beim Kernel Boot automatisch registriert wird) oder wenn du diesen selbst in deinem Plugin manuel registriert hast. 

Der Fehler lag darin dass im alten Plugin System im Backend dein Model nicht automatisch registriert war, was in der Netzwerk Console ausgeben wird:

image

 

Anbei die Sourcen wie es funktioniert.

Bootstrap.php

updateSchema();

$service = $this->get(‚shopware_attribute.crud_service‘);
$service->update(
‚s_articles_attributes‘,
‚attr_text‘,
‚single_selection‘,
[
‚label‘ => ‚MyText‘,
‚supportText‘ => ‚‘,
‚translatable‘ => false,
‚displayInBackend‘ => true,
‚position‘ => 1,
‚custom‘ => false,
‚entity‘ => \Shopware\CustomModels\MyModel\MyModel::class
],
null,
true
);

$this->subscribeEvent(‚Enlight_Controller_Action_PreDispatch_Backend_EntitySearch‘, ‚registerSearch‘);

return true;
}

public function registerSearch(Enlight_Event_EventArgs $args)
{
$this->registerCustomModels();
}

public function afterInit()
{
parent::afterInit();
$this->registerCustomModels();
}

protected function updateSchema(){
$this->registerCustomModels();

$em = $this->Application()->Models();

$tool = new \Doctrine\ORM\Tools\SchemaTool($em);

$classes = array(
$em->getClassMetadata(‚Shopware\CustomModels\Mymodel\Mymodel‘)
);

try {
$tool->dropSchema($classes);
} catch (Exception $e) {

}

$tool->createSchema($classes);
}
}

 

Model:

id;
}

/**

  • @param string $storagelocation
    */
    public function setName($name){
    $this->name= $name;
    }

/**

  • @return string
    */
    public function getName(){
    return $this->name;
    }
    }

 

Ordner Struktur:

image

Bitte auf Groß und Kleinschreibung bei den Klassen achten sonst kommt der AutoLoader nicht zurecht.

Hoffe das hilft euch weiter

Gruß Oliver

 

Hallo @Oliver Skroblin‍ ,

ich danke dir erst einmal für deine Hilfe und Unterstützung, diese hat mich sehr viel weiter gebracht.

An deiner Lösung wäre aber noch anzumerken, dass es nun zwingend nötig ist, im Model eine name - Spalte zu haben, auf die er bei dem Auswahlfeld zugreift. Thema ist für mich aber damit abgeschlossen, ich danke dir Halo.

Beste Grüße

Sebastian

Hi,

das stimmt aber stimmt auch wieder nicht ganz, die Komponenten suchen sich ein entsprechendes Feld nach definierter Priorisierung raus. Die Reihenfolge der Felder findest du in:

themes/Backend/ExtJs/backend/base/attribute/mixins/Shopware.attribute.SelectionFactory.js

    getRelevantFields: function() {
        return ['label', 'name', 'title', 'number', 'description','value'];
    },

Dieser Felder werden für die Anzeige in einer automatisch generierten Single und Multiselection verwendet

 

@Oliver Skroblin schrieb:

Hi,

das stimmt aber stimmt auch wieder nicht ganz, die Komponenten suchen sich ein entsprechendes Feld nach definierter Priorisierung raus. Die Reihenfolge der Felder findest du in:

themes/Backend/ExtJs/backend/base/attribute/mixins/Shopware.attribute.SelectionFactory.js

getRelevantFields: function() {
return [‚label‘, ‚name‘, ‚title‘, ‚number‘, ‚description‘,‚value‘];
},

Dieser Felder werden für die Anzeige in einer automatisch generierten Single und Multiselection verwendet

 

Hallo Oliver, 

vielen Dank für dein Feedback. Wenn man aber keins der 6 Felder genutzt hat, hat man trotzdem „null“ als Ausgabe. Aber das lässt sich auch wieder anpassen. Oder gibt es einen zusätzlichen Parameter, dem man den single selection mitgeben könnte?

Beste Grüße

Sebastian

Nur wenn du selbst eine SingleSelection implementierst.

Diese kann du so wie hier beschrieben im System registrieren:  Attribute system

@Oliver Skroblin schrieb:

Nur wenn du selbst eine SingleSelection implementierst.

Diese kann du so wie hier beschrieben im System registrieren:  https://developers.shopware.com/developers-guide/attribute-system/#define-own-single–and-multi-sel

Hallo Oliver,

danke für die Information, die Dokumentation kenn ich bereits. Ich habe mir jetzt einen funktionierenden „Workaround“ gebastelt, sodass als Feld nun „label“ genutzt wird und somit auch das richtige im Auswahlfeld angezeigt wird. Danke nochmal für deine Hilfe.

Beste Grüße

Sebastian