0

I have an extension property on Magento's Invoice class, and I'm trying to make an API method that sets the value of my extension attribute for a specific invoice. I'm using my class as an extension attribute when I get an invoice through the API, but in this example I just want to be able to quickly set its value without retrieving my invoice, setting its extension attribute, and then saving the entire invoice (since only the extension attribute changed).

My extension attribute has three columns:

  • entity_id (primary key)
  • invoice_id (foreign key to sales_invoice with unique constraint)
  • my_value

If my extension attribute doesn't already exist in the database table, this works correctly and inserts a row for my extension attribute for that invoice ID. However, if a row for that invoice ID already exists, it seems like this code tries to insert that row again rather than update the existing row.

How do I get this code to update the existing row, rather than try to insert a new row for an existing instance of my extension attribute?

interface MyExtensionInterface extends ExtensibleDataInterface
{
    const ENTITY_ID = "entity_id";
    const INVOICE_ID = "invoice_id";

    // Foreign key to the sales_invoice table
    public function getInvoiceId();
    public function setInvoiceId();

    public function getMyValue();
    public function setMyValue();

    public function getExtensionAttributes();
    public function setExtensionAttributes(\MyCompany\MyExtensionAttribute\Api\Data\MyExtensionInterface $extensionAttributes); 
}

class MyProvider implements MyExtensionProviderInterface
{
    public function __construct
    (
        EntityManager $entityManager,
        Loader $loader,
        MyExtensionFactory $myExtensionFactory
    ) {
        $this->entityManager = $entityManager;
        $this->loader = $loader;
        $this->myExtensionFactory = $myExtensionFactory;
    }

    // This is the method where I want to update the extension attribute's
    // value, and then update it in the database
    public function setMyExtensionValue($invoiceId, $value)
    {
        $ids = $this->loader->getMyExtensionAttributeByInvoiceId($invoiceId);

        if (count($ids) > 0)
        {
            $id = $ids[0];
            $myExtension = $this->myExtensionFactory->create();
            $this->entityManager->load($myExtension, $id);
        }
        else
        {
            $myExtension = $this->myExtensionFactory->create();
            $myExtension->setInvoiceId($invoiceId);
        }

        $myExtension->setMyValue($value);

        // This is where I'm getting an unique constraint violation
        $this->entityManager->save($myExtension);
    }       
}

class Loader
{
    private $metadataPool;
    private $resourceConnection;

    public function __construct
    (
        \Magento\Framework\EntityManager\MetadataPool $metadataPool,
        ResourceConnection $resourceConnection
    ) {
        $this->metadataPool = $metadataPool;
        $this->resourceConnection = $resourceConnection;
    }

    public function getMyExtensionAttributeByInvoiceId($invoiceId)
    {
        $metadata = $this->metadataPool->getMetadata(MyExtensionInterface::class);
        $connection = $this->resourceConnection->getConnection();
        $select = $connection
            ->select()
            ->from($metadata->getEntityTable(), MyExtensionInterface::ENTITY_ID)
            ->where(MyExtensionInterface::INVOICE_ID . ' = ?', $invoiceId);
        $ids = $connection->fetchCol($select);
        return $ids ?: [];
    }
}    
0

I figured it out. I needed to have getEntityId() as a member of MyExtensionInterface so that Magento would know that my row already exists.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.