Magento – class [] does not exist for custom extension_attributes over webapi

arrayextension-attributesmagento2restwebapi

I created a custom module to store the details of discount per items.
I have a custom tables to store informations (quote items, order items, invoice items), and I use a extension attributes to link these custom field to the main entities (quote, order, invoice).

Here is an excerpt of my extension_attributes.xml file :

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">


  <extension_attributes for="Magento\Sales\Api\Data\OrderInterface">
    <attribute code="vendor_discounts_order_items" type="Vendor\MultipleDiscounts\Api\Data\DiscountOrderItemInterface[]" />
  </extension_attributes>


</config>

As you can see I use a custom type Array : DiscountOrderItemInterface[].
Here is my interface file :

<?php
/**
 *
 * @category DiscountOrderItemInterface
 * @author   *******
 * @license  All right reserved to *****
 * @link     *******
 */

namespace Vendor\MultipleDiscounts\Api\Data;

/**
 * DiscountOrderItemInterface
 *
 * @category DiscountOrderItemInterface
 * @author   *********
 * @license  All right reserved to ****
 * @link     ********
 */
interface DiscountOrderItemInterface extends DiscountItemInterface
{

    const ORDER_ID = 'order_id';
    const ORDER_ITEM_ID = 'order_item_id';

    /**
     * getOrderId
     *
     * @return int
     */
    public function getOrderId();

    /**
     * setOrderId
     *
     * @param int $orderId orderId
     *
     * @return \Vendor\MultipleDiscounts\Api\Data\DiscountOrderItemInterface
     */
    public function setOrderId($orderId);

    /**
     * getOrderItemId
     *
     * @return int
     */
    public function getOrderItemId();

    /**
     * setOrderItemId
     *
     * @param int $orderItemId orderItemId
     *
     * @return \Vendor\MultipleDiscounts\Api\Data\DiscountOrderItemInterface
     */
    public function setOrderItemId($orderItemId);
}

It's all going well, I can store informations, and retrieve it, display it on both backend and frontend. But when I try to get orders over webapi REST Magento tries to instanciate DiscountOrderItemInterface[] class and I run into this error (has it does not exists) :

Array
(
    [message] => Class \Vendor\MultipleDiscounts\Api\Data\DiscountOrderItemInterface[] does not exist
    [code] => -1
    [trace] => #0 /httpdocs/vendor/magento/framework/Reflection/MethodsMap.php(149): ReflectionClass->__construct('\\Vendor\\Mult...')
#1 /httpdocs/vendor/magento/framework/Reflection/MethodsMap.php(100): Magento\Framework\Reflection\MethodsMap->getMethodMapViaReflection('\\Vendor\\Mult...')
#2 /httpdocs/vendor/magento/framework/Reflection/DataObjectProcessor.php(77): Magento\Framework\Reflection\MethodsMap->getMethodsMap('\\Vendor\\Mult...')
#3 /httpdocs/var/generation/Magento/Framework/Reflection/DataObjectProcessor/Proxy.php(95): Magento\Framework\Reflection\DataObjectProcessor->buildOutputDataArray(Object(Vendor\MultipleDiscounts\Model\ResourceModel\DiscountOrderItem\Collection), '\\Vendoror\\Mult...')
#4 /httpdocs/vendor/magento/framework/Reflection/ExtensionAttributesProcessor.php(119): Magento\Framework\Reflection\DataObjectProcessor\Proxy->buildOutputDataArray(Object(Vendor\MultipleDiscounts\Model\ResourceModel\DiscountOrderItem\Collection), '\\Vendor\\Mult...')
#5 /httpdocs/vendor/magento/framework/Reflection/DataObjectProcessor.php(104): Magento\Framework\Reflection\ExtensionAttributesProcessor->buildOutputDataArray(Object(Magento\Sales\Api\Data\OrderExtension), '\\Magento\\Sales\\...')
#6 /httpdocs/vendor/magento/framework/Webapi/ServiceOutputProcessor.php(107): Magento\Framework\Reflection\DataObjectProcessor->buildOutputDataArray(Object(Magento\Sales\Model\Order\Interceptor), '\\Magento\\Sales\\...')
#7 /httpdocs/vendor/magento/framework/Webapi/ServiceOutputProcessor.php(59): Magento\Framework\Webapi\ServiceOutputProcessor->convertValue(Object(Magento\Sales\Model\Order\Interceptor), '\\Magento\\Sales\\...')
#8 /httpdocs/vendor/magento/module-webapi/Controller/Rest.php(312): Magento\Framework\Webapi\ServiceOutputProcessor->process(Object(Magento\Sales\Model\Order\Interceptor), 'Magento\\Sales\\A...', 'get')
#9 /httpdocs/vendor/magento/module-webapi/Controller/Rest.php(216): Magento\Webapi\Controller\Rest->processApiRequest()
#10 /httpdocs/var/generation/Magento/Webapi/Controller/Rest/Interceptor.php(24): Magento\Webapi\Controller\Rest->dispatch(Object(Magento\Framework\App\Request\Http))
#11 /httpdocs/vendor/magento/framework/App/Http.php(135): Magento\Webapi\Controller\Rest\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#12 /httpdocs/vendor/magento/framework/Interception/Interceptor.php(146): Magento\Framework\App\Http->launch()
#13 /httpdocs/var/generation/Magento/Framework/App/Http/Interceptor.php(26): Magento\Framework\App\Http\Interceptor->___callPlugins('launch', Array, Array)
#14 /httpdocs/vendor/magento/framework/App/Bootstrap.php(258): Magento\Framework\App\Http\Interceptor->launch()
#15 /httpdocs/index.php(39): Magento\Framework\App\Bootstrap->run(Object(Magento\Framework\App\Http\Interceptor))
#16 {main}
)

any help would be appreciated.

Best Answer

I finally manage to resolve this issue. After digging into the Magento core, I found that in the \Magento\Framework\Reflection\ExtensionAttributeProcessor::buildOutputDataArray method, Magento get the type of the extension object attribute (in my case : Vendor\MultipleDiscounts\Api\Data\DiscountOrderItemInterface[]). If type is array, then Magento will substring the [] characters.

In my case the type was wrong : object Collection.

I use an observer to set my extension_attribute (sales order load after) and I have to change my code like this :

Before :

...
$orderExtension = $order->getExtensionAttributes();
if ($orderExtension == null) {
    $orderExtension = $this->orderExtensionFactory->create();
}
$discountOrderItems = $this->discountOrderItemRepository->getListByOrderId($order->getId());
$orderExtension->setDiscountsOrderItems($discountOrderItems);
...

After :

...
$orderExtension = $order->getExtensionAttributes();
if ($orderExtension == null) {
    $orderExtension = $this->orderExtensionFactory->create();
}
$discountOrderItems = $this->discountOrderItemRepository->getListByOrderId($order->getId());
$orderExtension->setDiscountsOrderItems($discountOrderItems->getItems());
...

I just add ->getItems() method on my $discountOrderItems collection object to return an array of object.

Hope this can help others.

Related Topic