Skip to content

Can’t get extension attribute in a plugin

I am trying to create a module that uploads Category image (as Category extension attribute) via REST API. The problem is that I can’t even fetch extension attributes in afterSave method of my Plugin with the lines of code below:

$extensionAttributes = $category->getExtensionAttributes() ?: $this->categoryExtensionFactory->create();

And then, can’t save this attribute in my custom table due to Integrity constraint violation (beause my extension attribute has NULL value):

[2022-09-20 00:21:02] main.ERROR: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'api_uploaded_image' cannot be null, query was: INSERT INTO `sl_category_image_via_api_attribute` (`category_id`, `api_uploaded_image`) VALUES (?, ?) [] []

Though, obviously, extension attribute is set in my API request to
https://{{magento2_root}}/rest/async/bulk/V1/categories

{
  "id": 352,
  "parent_id": 229,
  "name": "Мобільний телефон Nokia 108100",
  "is_active": true,
  "position": 1,
  "level": 4,
  "children": "",
  "created_at": "2022-09-18 18:48:16",
  "updated_at": "2022-09-18 18:48:16",
  "path": "1/2/161/229/352",
  "available_sort_by": [],
  "include_in_menu": true,
  "extension_attributes": {
    "api_uploaded_image": "YnsA"
  },
  .
  .
  .
} 

1. db_schema.xml

<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="sl_category_image_via_api_attribute" resource="default" engine="innodb" comment="Category Images Sent Via API Table">
        <column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Entity ID"/>
        <column xsi:type="int" name="category_id" padding="10" unsigned="true" nullable="false" identity="false" comment="Category ID"/>
        <column xsi:type="varchar" name="api_uploaded_image" nullable="false" comment="Base64 Encoded Images"/>
        <column xsi:type="timestamp" name="created_at" on_update="false" nullable="false" default="CURRENT_TIMESTAMP" comment="Create Time"/>
        <column xsi:type="timestamp" name="updated_at" on_update="true" nullable="false" default="CURRENT_TIMESTAMP" comment="Update Time"/>
        <constraint xsi:type="primary" referenceId="PRIMARY">
            <column name="entity_id"/>
        </constraint>
        <constraint xsi:type="foreign" referenceId="SL_CTGRY_IMG_VIA_API_ATTR_CATEGORY_ID_CATALOG_CTGRY_ENTT_ENTT_ID"
                    table="sl_category_image_via_api_attribute" column="category_id" referenceTable="catalog_category_entity"
                    referenceColumn="entity_id" onDelete="CASCADE"/>
    </table>
</schema>

In a case I set nullable=”true” for name=”api_uploaded_image” attribute in db_schema.xml:

<column xsi:type="varchar" name="api_uploaded_image" nullable="true" comment="Base64 Encoded Images"/>

then I can save my custom entity in a custom table with “api_uploaded_image” column and NULL value:

How can I retrive category extension attribute in a Plugin (afterSave method) and then save it to my custom table?

I will be appreciate for your help.
Thanks in advance.

2. The full code of Plugin

<?php

declare(strict_types=1);

namespace SlCategoryImageApiUploadPlugin;

use MagentoCatalogApiDataCategoryExtensionFactory;
use SlCategoryImageApiUploadApiManagementInterface;
use MagentoCatalogApiDataCategoryInterface;
use MagentoCatalogApiDataCategorySearchResultsInterface;
use MagentoCatalogApiCategoryRepositoryInterface;
use SlCategoryImageApiUploadModelAttributesFactory;
use SlCategoryImageApiUploadModelAttributesResource;
use PsrLogLoggerInterface;

class CategoryRepositoryPlugin
{
    /**
     * @var LoggerInterface
     */
    private LoggerInterface $logger;

    /**
     * @var ManagementInterface
     */
    private ManagementInterface $management;

    /**
     * @var AttributesFactory
     */
    private AttributesFactory $attributesFactory;
    /**
     * @var AttributesResource
     */
    private AttributesResource $attributesResource;
    /**
     * @var CategoryExtensionFactory
     */
    private CategoryExtensionFactory $categoryExtensionFactory;

    /**
     * CategoryRepositoryPlugin constructor.
     * @param AttributesFactory $attributesFactory
     * @param AttributesResource $attributesResource
     * @param ManagementInterface $management
     * @param CategoryExtensionFactory $categoryExtensionFactory
     */
    public function __construct(
        AttributesFactory $attributesFactory,
        AttributesResource $attributesResource,
        CategoryExtensionFactory $categoryExtensionFactory,
        ManagementInterface $management,
        LoggerInterface $logger
    ) {
        $this->attributesFactory = $attributesFactory;
        $this->attributesResource = $attributesResource;
        $this->categoryExtensionFactory = $categoryExtensionFactory;
        $this->management = $management;
        $this->logger = $logger;
    }

    /**
     * @param CategoryRepositoryInterface $subject
     * @param CategorySearchResultsInterface $categorySearchResult
     * @return CategorySearchResultsInterface
     */
    public function afterGetList(
        CategoryRepositoryInterface $subject,
        CategorySearchResultsInterface $categorySearchResult
    ): CategorySearchResultsInterface {
        foreach ($categorySearchResult->getItems() as $category) {
            $this->afterGet($subject, $category);
        }
        return $categorySearchResult;
    }

    /**
     * @param CategoryRepositoryInterface $subject
     * @param CategoryInterface $category
     * @return CategoryInterface
     */
    public function afterGet(
        CategoryRepositoryInterface $subject,
        CategoryInterface $category
    ): CategoryInterface {
        $categoryAttribute = $this->management->getByCategoryId((int) $category->getId());

        $extensionAttributes = $category->getExtensionAttributes();
        $extensionAttributes->setCategoryId($categoryAttribute->getCategoryId());
        $extensionAttributes->setApiUploadedImage($categoryAttribute->getApiUploadedImage());

        $category->setExtensionAttributes($extensionAttributes);

        return $category;
    }

    /**
     * @param CategoryRepositoryInterface $subject
     * @param CategoryInterface $category
     * @return CategoryInterface
     */
    public function afterSave(
        CategoryRepositoryInterface $subject,
        CategoryInterface $category
    ): CategoryInterface {
//        $categoryAttribute = $this->management->getByCategoryId((int) $category->getId());
//        $categoryCollection = $this->categoryFactory->create()->getAttributesCollection();

        $extensionAttributes = $category->getExtensionAttributes() ?: $this->categoryExtensionFactory->create();
        if ($extensionAttributes !== null && $extensionAttributes->getApiUploadedImage() !==null) {
//            $extensionAttributes->setApiUploadedImage($extensionAttributes->getApiUploadedImage());
            $attributesEntity = $this->attributesFactory->create();
            $attributesEntity->setCategoryId($category->getId());
            $attributesEntity->setApiUploadedImage($extensionAttributes->getApiUploadedImage());
//            $this->logger->debug('valuer=' .serialize($attributesEntity));
            $this->management->save($attributesEntity);
//            $this->attributesRepository->save($attributesEntity);
//            $this->$subject->save();
        }
//        $extensionAttributes->setCategoryId($categoryAttribute->getCategoryId());
//        $extensionAttributes->setApiUploadedImage($categoryAttribute->getApiUploadedImage());

//        $category->setExtensionAttributes($extensionAttributes);

        return $category;
    }
}