Daten lesen von entity extension

Hallo,

ich habe das Produkt-Objekt erweitert (lt. Handbuch).
Schreiben ins neue Feld funktioniert mit dem SQL-Codeschnipsel.

Mit folgender SQL-Anweisung hole ich mir das Produkt:

...
$product = $this->productRepository
            ->search(
                new Criteria([$idMainProduct]),
                $context
            )
            ->first();
...

Wie kann ich vom Objekt $product die Daten der Erweiterung lesen?

VG

Nur so am Rande, damit es nicht zu sprachlichen Verwirrungen kommt: das ist keine SQL-Anweisung, das ist ein PHP-Objekt.

Es müsste $product->getExtensions() sein.

Hi,
@Max_Shop danke für deine Antwort und auch zum Hinweis des Wording.

Die richtige Methode heißt getExtension(%myExtension%) .

Aber ich habe weiterhin Probleme, ich habe einen Datensatz gespeichert:


Dieser wurde mit folgenden Code eingefügt:

...
$this->productRepository
     ->upsert([[
         'id' => $idMainProduct,
         'components' => [
               'components' => $idProductComponent
         ]
]], $context);
....

Auslesen tu ich den Datensatz mit o.g. Anweisung:

$product = $this->productRepository
            ->search(
                new Criteria([$idMainProduct]),
                $context
            )
            ->first();

Dann mit $product->getExtension('components') bekomme ich ein Objekt meiner Klasse(?)
leider verstehe die Annotation nicht:

Returns a single extension struct element of this class

Deutsch

Gibt ein einzelnes Erweiterungsstrukturelement (<— ???) dieser Klasse zurück

…meint? Hab ich nun ein Objekt meiner Klasse?

Wie auch immer, der dump zeigt die ein objekt der ExtensionEntity-Klasse:

...
object(ProductComposer\Extension\ProductComponentEntity)#2179 (12) {
  ["components":"ProductComposer\Extension\ProductComponentEntity":private]=>
  array(0) {  *<========================= leer?*
  }
  ["_uniqueIdentifier":protected]=>
  string(32) "3d1e39d16c1341c8b7cb9c514ff4c8b0"
  ["versionId":protected]=>
  NULL
  ["translated":protected]=>
  array(0) {
  }
  ["createdAt":protected]=>
  object(DateTimeImmutable)#2198 (3) {
    ["date"]=>
    string(26) "2022-06-13 13:18:42.084000"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
...

Die Zugehörige Klasse:

<?php declare(strict_types=1);

namespace ProductComposer\Extension;

use Shopware\Core\Framework\DataAbstractionLayer\Entity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityIdTrait;


class ProductComponentEntity extends Entity
{
    use EntityIdTrait;

    private array $components = [];

    /**
     * @return array
     */
    public function getComponents(): array
    {
        return $this->components;
    }

    /**
     * @param string $idComponent
     */
    public function addComponent(string $idComponent): void
    {
        $this->components[] = $idComponent;
    }


}

Und hier meinProblem: die Eigenschaft components bleibt leer? Warum?

Die Property $components ist private. In einem print_r bekommst du keine privat Werte. Da musst du per $product->getExtension(‚components‘)->getComponents() darauf zugreifen.

$product->getExtension('components')->getComponents() ja, das ist klar.
Aber da ja die Variable leer ist, zeigt die Methode genau was sie soll:

array(0) {
}

Die Frage ist, warum wird die Spalte product_component.components nicht ausgelesen oder warum liefert die Abfrage nichts?

Btw, ich such gerade die Möglichkeit des debuggen meines requesst. Eben zu schauen, was an die DB übergeben wird bzw was zurückkommt.
Ich nutze die Docker-Umgebung zum entwickeln. So wie ich das sehe, ist da kein xdebug vorinstalliert. Gibt es dazu irgend eine Doku?

Wie hast du die Extension angelegt? Das sie nachgeladen werden muss oder immer geladen werden soll? Oder trifft das nur auf Assoziationen zu, bin mir gerade nicht ganz sicher.

Wie hast du die Extension angelegt?

@Max_Shop Was meinst du damit? Ich habe das Teil mit dem Handbuch erstellt.

Das sie nachgeladen werden muss oder immer geladen werden soll?

Mmmh, verstehe ich auch nicht den Gedanken. Die Extension ist ein Service, also demnach immer geladen denke ich:

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="ProductComposer\Extension\ProductComponentExtension">
            <tag name="shopware.entity.extension"/>
        </service>
        <service id="ProductComposer\Extension\ProductComponentExtensionDefinition">
            <tag name="shopware.entity.definition" entity="product_component_extension" />
        </service>
        <service id="ProductComposer\Controller\ProductComponentController" public="true">
            <argument type="service" id="product.repository"/>
            <call method="setContainer">
                <argument type="service" id="service_container"/>
            </call>
        </service>
    </services>
</container>

Außerdem, das Objekt ist ja nicht gänzlich leer, sondern nur die components kommen nicht an

Assoziationen können so angelegt werden, dass sie entweder immer mit dem Objekt geladen werden oder aktiv nachgeladen werden müssen. Ich weiß nicht, ob es bei Extension das gleiche ist. Müsstest du mal nachlesen.

Assoziationen … oder aktiv nachgeladen werden müssen.

@Max_Shop Ok, also die Konfiguration zum Nachladen oder mit dem Objekt geladen steht auf true:

// ProductComponentExtension.php
...
class ProductComponentExtension extends EntityExtension
{
    public function extendFields(FieldCollection $collection): void
    {
        $collection->add(
            new OneToOneAssociationField(
                'components',
                'id',
                'product_id',
                ProductComponentExtensionDefinition::class,
                true <========= association should always be loaded by default 
            )
        );
    }

    public function getDefinitionClass(): string
    {
        return ProductDefinition::class;
    }
}
...

Welche Datensätze stehen denn in der Tabelle product_component_extension?

@abdullah Woher holst du den Namen (product_component_extension) der Tabelle, hab ich da etwas übersehen? Die Tabelle heißt product_component

Die angefragten Daten stehen oben in meiner Antwort

@rammi22 Im Service ist bei der Definition die Entity mit product_component_extension angegeben. Daher der Name der Tabelle.

Ich weiß jetzt nicht, wie du die Entity, Definition und die Migration usw. jeweils angelegt hast. Kann sein, dass hier ein Fehler noch vorhanden ist.

Kann sein, dass hier ein Fehler noch vorhanden ist

@abdullah ja, das schließe ich ja nicht aus. Ich habe den Wert der Entity geändert:

<service id="ProductComposer\Extension\ProductComponentExtensionDefinition">
            <tag name="shopware.entity.definition" entity="product_component" />
        </service>

…das Verhalten hat sich dennoch nicht geändert.

Ich habe das SQL-Statement debuggt, die entscheidene Stelle:

SELECT
...
`product.components`.`id` as `product.components.id`, `product.components`.`product_id` as `product.components.productId`, `product.components`.`components` as `product.components.components`, `product.components`.`created_at` as `product.components.createdAt`, `product.components`.`updated_at` as `product.components.updatedAt`,
...
LEFT JOIN `product_component` `product.components` ON `product`.`id` = `product.components`.`product_id` WHERE (`product`.`version_id` = :version) AND (`product`.`id` IN (:ids))

Ich erkenne nicht, warum product_component.components nicht mitgeliefert wird. Das Feld product_component.createtAt wird doch auch ausgelesen. Erkennbar im var_dump von $product->getExtension('components'):

/app/custom/plugins/ProductComposer/src/Controller/ProductComponentController.php:111:
object(ProductComposer\Extension\ProductComponentEntity)[2179]
  private array 'components' => 
    array (size=0)
      empty
  protected '_uniqueIdentifier' => string '3d1e39d16c1341c8b7cb9c514ff4c8b0' (length=32)
  protected 'versionId' => null
  protected 'translated' => 
    array (size=0)
      empty
  protected 'createdAt' => 
    object(DateTimeImmutable)[2185]
      public 'date' => string '2022-06-13 13:20:42.084000' (length=26)
      public 'timezone_type' => int 3
      public 'timezone' => string 'UTC' (length=3)
  protected 'updatedAt' => null
  private '_entityName' (Shopware\Core\Framework\DataAbstractionLayer\Entity) => string 'product_component' (length=17)
  private ?Shopware\Core\Framework\DataAbstractionLayer\FieldVisibility '_fieldVisibility' (Shopware\Core\Framework\DataAbstractionLayer\Entity) => 
    object(Shopware\Core\Framework\DataAbstractionLayer\FieldVisibility)[2181]
      private array 'internalProperties' => 
        array (size=0)
          empty
  protected 'extensions' => 
    array (size=2)
      'foreignKeys' => 
        object(Shopware\Core\Framework\Struct\ArrayStruct)[2177]
          protected 'data' => 
            array (size=0)
              empty
          protected 'apiAlias' => null
          protected 'extensions' => 
            array (size=0)
              empty
      'internal_mapping_storage' => 
        object(Shopware\Core\Framework\Struct\ArrayStruct)[2180]
          protected 'data' => 
            array (size=0)
              empty
          protected 'apiAlias' => null
          protected 'extensions' => 
            array (size=0)
              empty
  protected 'id' => string '3d1e39d16c1341c8b7cb9c514ff4c8b0' (length=32)
  public 'productId' => string 'ac0456e2c692430691240c8d4d831e12' (length=32)
  public 'product' => null

Zumindest ausgelesen wird das Feld (debug breakpoint $row):

0 = {array} [93]
...
 product.components.components = "["123abc", "832c27bc5cf64ef1aba549ea38df953c", "test"]"
...

Also irgendwie beim Füllen des Objekt läuft was falsch…

Ok, finally…

In der ProductComponentEntity war die Eigenschaft $components als private deklariert.

Richtig ist, und so auch im Handbuch beschrieben, die Eigenschaft muß protected sein.

...
class ProductComponentEntity extends Entity
{
    use EntityIdTrait;

    protected array $components = [];

    ...
}
...

VG