Plugin: beim Erstellen einer Entity kommt "Expected data to be array"

Hallo zusammen,

ich habe in einem Plugin eine Entity Device mit einer ManyToMany-Assoziation auf eine andere, eigene Entity ArticleGroup und zwei ManyToOne-Assoziationen auf eine andere eigene Entity Type und auf ProductManufacturer, siehe:

class DeviceEntity extends Entity
{
    use EntityIdTrait;

    /**
     * @var string
     */
    protected $deviceId;

    /**
     * @var DateTime
     */
    protected $update;

    /**
     * @var string
     */
    protected $modelNumber;

    /**
     * @var string
     */
    protected $additional;

    /**
     * @var string
     */
    protected $identNumber;

    /**
     * @var ProductManufacturerEntity
     */
    protected $productManufacturer;

    /**
     * @var TypeEntity
     */
    protected $type;

    /**
     * @var ArticleGroupCollection
     */
    protected $articleGroups;

    /**
     * @var int
     */
    protected $active;

...
}

Ich habe mein Plugin in Anlehnung an das Tutorial Shopware 6: Step 1: Introduction erstellt, einschließlich der Vue-Komponenten für den Admin-Bereich.

Ich kann Instanzen meiner eigenen primitiven Entities Type und ArticleGroup erstellen (die kommen beide ohne Assoziationen aus), aber wenn ich eine Instanz von Device erstellen möchte, was in folgenden Payload für den POST-Request mündet:

{
"productManufacturerId":"112a0ca7de2e42c4866d5f83e9de1c45",
"typeId":"0a94fa60001c49a6a7d4ceb19063c24a",
"deviceId":"ID",
"modelNumber":"12",
"additional":"zusätzlich",
"identNumber":"21",
"articleGroups":[{"id":"37979f2b3eeb4b7db7f5dac75a3fa9a2"}],
"active":1,
"id":"1d31f43561234b428d19c9bf640fcdaa"
}

dann kommt ein Bad Request (HTTP-Code 400) mit dem Fehler:

{
  "errors": [
     {
        "status":"400",
        "code":"FRAMEWORK__WRITE_MALFORMED_INPUT",
        "title":"Bad Request",
        "detail":"Expected data to be array.",
        "meta":{
          "parameters":[]
        }
     }
  ]
}

Leider werde ich aus dieser Fehlermeldung nicht schlau. Hat jemand eine Idee?

Danke!
Michael

Ok, ich habe nach etwas Debugging jetzt gesehen, dass die Api ein Array für den Key „productManufacturer“ erwartet, aber nichts für „productManufacturerId“. Nur leider hat das per Vue generierte Formular bei v-model=„productManufacturer“ statt v-model=„productManufacturerId“ gar nichts für „productManufacturer“ gesendet. Also weiter debuggen…

Irgendwie scheint die Api Werte für das Feld „productManufacturer“ zu erwarten, aber senden kann ich lediglich „productManufacturerId“, da in der platform/src/Administration/Resources/app/administration/src/core/data-new/changeset-generator.data.js der Fall für ‚many_to_one‘ leer ist.

Meine Formular-Definition sieht wie folgt aus:

                {{ device.productManufacturer }}
                
                

                {{ device.type }}

und meine Entity-Definition:
 

    protected function defineFields(): FieldCollection
    {
        return new FieldCollection([
            (new FkField('product_manufacturer_id', 'productManufacturerId', ProductManufacturerDefinition::class))->addFlags(new Inherited(), new Required()),
            (new ReferenceVersionField(ProductManufacturerDefinition::class))->addFlags(new Inherited(), new Required()),

            (new FkField('type_id', 'typeId', TypeDefinition::class))->addFlags(new Inherited()),
            
            (new IdField('id', 'id'))->addFlags(new PrimaryKey(), new Required()),
            (new StringField('device_id', 'deviceId'))->addFlags(new Required()),
            new DateTimeField('update', 'update'),
            new StringField('model_number', 'modelNumber'),
            new StringField('additional', 'additional'),
            new StringField('ident_number', 'identNumber'),
            (new ManyToOneAssociationField('productManufacturer', 'product_manufacturer_id', ProductManufacturerDefinition::class))->addFlags(new Required()),
            new ManyToOneAssociationField('type', 'type_id', TypeDefinition::class),
            new ManyToManyAssociationField('articleGroups', ArticleGroupDefinition::class, DeviceArticleGroupDefinition::class, 'device_id', 'article_group_id'),
            new IntField('active', 'active', 0, 1)
        ]);
    }

Auch sonst sehe ich im Shopware-Code überall, dass sw-entity-single-select immer das v-model auf das entity.andereEntityId statt auf entity.andereEntity verweisen lassen.

Ich habe zum Test mal den Manufacturer bei einem Produkt geändert und da wird im Payload des POST-Api-Requests auch nur {„manufacturerId“:„112a0ca7de2e42c4866d5f83e9de1c45“} gesendet.

Hat jemand eine Idee, warum Shopware für meine Device-Entity ein Array für die ManyToOne-Assoziation erwartet?

1 „Gefällt mir“

Ich habe es nach langem Debuggen selbst gefunden:
1.) habe ich den vierten Parameter ‚id‘ in folgendem Statement vergessen

new ManyToOneAssociationField('productManufacturer', 'product_manufacturer_id', ProductManufacturerDefinition::class, 'id')

2.) habe ich alle Flags 

new Inherited()

entfernt.

Ich hoffe, dass es anderen weiterhilft, die evtl. vor einem ähnlichen Problem stehen.

1 „Gefällt mir“

Danke, dass du deine Lösung gepostet hast :v:

@Michael86 schrieb:

Ich habe es nach langem Debuggen selbst gefunden:
1.) habe ich den vierten Parameter ‚id‘ in folgendem Statement vergessen

new ManyToOneAssociationField(‚productManufacturer‘, ‚product_manufacturer_id‘, ProductManufacturerDefinition::class, ‚id‘)

2.) habe ich alle Flags 

new Inherited()

entfernt.

Ich hoffe, dass es anderen weiterhilft, die evtl. vor einem ähnlichen Problem stehen.

Zur Ergänzung, da ich zur Zeit auch damit zu tun habe:

Es lag bei dir aller Wahrscheinlichkeit nach an 2.) und nicht an 1.), da im Konstruktor der Klasse ManyToOneAssociationField bereits _string $referenceField = ‚id‘ _als Default-Wert des vierten Feldes gesetzt wird.

Ja, da hast du recht.

Noch eine Anmerkung:

Was mir auch gerade aufgefallen ist (ich hatte noch was geändert):

(new ManyToOneAssociationField('productManufacturer', 'product_manufacturer_id', ProductManufacturerDefinition::class))->addFlags(new Required()),

Er mag es anscheinend nicht, wenn man dem ManyToOneAssociationField das Flag “new Required()” mitgibt. Möglicherweise war das die eigentliche Ursache, da das Backend dann womöglich ein Feld ‘productManufacturer’ im POST-Request erwartet, während das eigentlich nötige Feld ja  ‘productManufacturerId’ ist.

Stimmt, das macht auch noch einen Unterschied. Wenn die Required-Flag auf dem ManyToOne-field gesetzt ist, funktionieren (Creation-)Requests mit FkKey nicht mehr; wenn man stattdessen ein Objekt übergibt, geht es noch. Scheint aber generell keine gute Idee zu sein.

Ich erlaube mir mal, hier auch meinen beantworteten Thread zu verlinken, da die dortigen Überlegungen in diesem Kontext ebenfalls interessant sein dürften.

Gut, danke, dass du deinen Thread auch verlinkt hast. Diese feinen Unterschiede können jemandem wie mir, der zum ersten Mal ein solches Plugin schreibt, wirklich den Nerv rauben, gerade auch, weil die zugehörige Fehlermeldung keinen Hinweis auf die Ursache gibt.

Ja, hier genauso, da ging viel Zeit für drauf, um das zu durchschauen. Dir auch danke fürs Posten deiner Lösungen.