Magento 2 Fatal Error – Save() Must Be an Instance Interface

apifatal errormagento2model

Trying to save record in admin grid with create API interface but getting fatal Error link below

Fatal error: Uncaught TypeError: Argument 1 passed to
Mage2\Inquiry\Model\InquiryRepository::save() must be an instance of
Mage2\Inquiry\Api\Data\InquiryInterface, instance of
Mage2\Inquiry\Model\Inquiry given, called in
/var/www/html/2-3/app/code/Mage2/Inquiry/Controller/Adminhtml/Inquiry/Save.php
on line 89 and defined in
/var/www/html/2-3/app/code/Mage2/Inquiry/Model/InquiryRepository.php:114

Code of file Save.php under controller

namespace Mage2\Inquiry\Controller\Adminhtml\Inquiry;

use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Backend\App\Action\Context;
use Mage2\Inquiry\Api\InquiryRepositoryInterface;
use Mage2\Inquiry\Model\Inquiry;
use Mage2\Inquiry\Model\InquiryFactory;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Registry;


class Save extends \Mage2\Inquiry\Controller\Adminhtml\Inquiry implements HttpPostActionInterface
{

    /**
     * @var DataPersistorInterface
     */
    protected $dataPersistor;

    /**
     * @var InquiryFactory
     */
    private $inquiryFactory;

    /**
     * @var InquiryRepositoryInterface
     */
    private $inquiryRepository;

    /**
     * @param Context $context
     * @param Registry $coreRegistry
     * @param DataPersistorInterface $dataPersistor
     * @param InquiryFactory|null $inquiryFactory
     * @param InquiryRepositoryInterface|null $inquiryRepository
     */
    public function __construct(
        Context $context,
        Registry $coreRegistry,
        DataPersistorInterface $dataPersistor,
        InquiryFactory $inquiryFactory = null,
        InquiryRepositoryInterface $inquiryRepository = null
    ) {
        $this->dataPersistor = $dataPersistor;
        $this->inquiryFactory = $inquiryFactory
            ?: \Magento\Framework\App\ObjectManager::getInstance()->get(InquiryFactory::class);
        $this->inquiryRepository = $inquiryRepository
            ?: \Magento\Framework\App\ObjectManager::getInstance()->get(InquiryRepositoryInterface::class);
        parent::__construct($context, $coreRegistry);
    }

    /**
     * Save action
     *
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
        $resultRedirect = $this->resultRedirectFactory->create();
        $data = $this->getRequest()->getPostValue();
        if ($data) {
            if (isset($data['status']) && $data['status'] === 'true') {
                $data['status'] = Inquiry::STATUS_ENABLED;
            }
            if (empty($data['inquiry_id'])) {
                $data['inquiry_id'] = null;
            }

            /** @var \Mage2\Inquiry\Model\Inquiry $model */
            $model = $this->inquiryFactory->create();

            $id = $this->getRequest()->getParam('inquiry_id');
            if ($id) {
                try {
                    $model = $this->inquiryRepository->getById($id);
                } catch (LocalizedException $e) {
                    $this->messageManager->addErrorMessage(__('This inquiry no longer exists.'));
                    return $resultRedirect->setPath('*/*/');
                }
            }

            $model->setData($data);

            try {
                $this->inquiryRepository->save($model);
                $this->messageManager->addSuccessMessage(__('You saved the inquiry.'));
                $this->dataPersistor->clear('mage2_inquiry');
                return $this->processInquiryReturn($model, $data, $resultRedirect);
            } catch (LocalizedException $e) {
                $this->messageManager->addErrorMessage($e->getMessage());
            } catch (\Exception $e) {
                $this->messageManager->addExceptionMessage($e, __('Something went wrong while saving the inquiry.'));
            }

            $this->dataPersistor->set('mage2_inquiry', $data);
            return $resultRedirect->setPath('*/*/edit', ['inquiry_id' => $id]);
        }
        return $resultRedirect->setPath('*/*/');
    }

    /**
     * Process and set the Inquiry return
     *
     * @param \Magento\Cms\Model\Inquiry $model
     * @param array $data
     * @param \Magento\Framework\Controller\ResultInterface $resultRedirect
     * @return \Magento\Framework\Controller\ResultInterface
     */

    private function processInquiryReturn($model, $data, $resultRedirect)
    {
        $redirect = $data['back'] ?? 'close';

        if ($redirect ==='continue') {
            $resultRedirect->setPath('*/*/edit', ['inquiry_id' => $model->getId()]);
        } else if ($redirect === 'close') {
            $resultRedirect->setPath('*/*/');
        } else if ($redirect === 'duplicate') {
            $duplicateModel = $this->inquiryFactory->create(['data' => $data]);
            $duplicateModel->setId(null);
            $duplicateModel->setStatus(Inquiry::STATUS_DISABLED);
            $this->inquiryRepository->save($duplicateModel);
            $id = $duplicateModel->getId();
            $this->messageManager->addSuccessMessage(__('You duplicated the inquiry.'));
            $this->dataPersistor->set('mage2_inquiry', $data);
            $resultRedirect->setPath('*/*/edit', ['inquiry_id' => $id]);
        }
        return $resultRedirect;
    }
}

InquiryInterface.php

namespace Mage2\Inquiry\Api\Data;

/**
 * Inquiry Interface
 * @api
 * @since 100.0.2
 */
interface InquiryInterface
{
    /**#@+
     * Constants for keys of data array. Identical to the name of the getter in snake case
     */
    const INQUIRY_ID      = 'inquiry_id';
    const NAME            = 'name';
    const MOBILE_NUMBER   = 'mobile_number';
    const MESSAGE         = 'message';
    const EMAIL           = 'email';
    const PRODUCT_ID      = 'product_id';
    const STATUS          = 'status';
    const DISPLAY_FRONT   = 'display_front';
    const ADMIN_MESSAGE   = 'admin_message';
    /**#@-*/

    /**
     * Get ID
     *
     * @return int|null
     */
    public function getId();

    /**
     * Get Name
     *
     * @return string
     */
    public function getName();

    /**
     * Get Mobile Number
     *
     * @return string|null
     */
    public function getMobileNumber();

    /**
     * Get message
     *
     * @return string|null
     */
    public function getMessage();

    /**
     * Get email
     *
     * @return string|null
     */
    public function getEmail();

    /**
     * Get Product Id
     *
     * @return string|null
     */
    public function getProductId();

    /**
     * Get Display in front setting
     *
     * @return string|null
     */
    public function getDisplayFront();

    /**
     * Get Admin message
     *
     * @return string|null
     */
    public function getAdminMessage();

    /**
     * Get status
     *
     * @return bool|null
     */
    public function getStatus();

    /**
     * Set ID
     *
     * @param int $id
     * @return InquiryInterface
     */
    public function setId($id);

    /**
     * Set Name
     *
     * @param string $name
     * @return InquiryInterface
     */
    public function setName($name);

    /**
     * Set MobileNumber
     *
     * @param string $mobile_number
     * @return InquiryInterface
     */
    public function setMobileNumber($mobile_number);

    /**
     * Set message
     *
     * @param string $message
     * @return InquiryInterface
     */
    public function setMessage($message);

    /**
     * Set Email
     *
     * @param string $email
     * @return InquiryInterface
     */
    public function setEmail($email);

    /**
     * set ProductId
     *
     * @param int $product_id
     * @return InquiryInterface
     */
    public function setProductId($product_id);

    /**
     * Set Display Front setting
     *
     * @param bool|int $display_front
     * @return InquiryInterface
     */
    public function setDisplayFront($display_front);

    /**
     * Set Admin Message
     *
     * @param string $admin_message
     * @return InquiryInterface
     */
    public function setAdminMessage($admin_message);

    /**
     * Set Status
     *
     * @param bool|int $status
     * @return InquiryInterface
     */
    public function setStatus($status);
}

Best Answer

In the etc/di.xml, you need to add preference for \Mage2\Inquiry\Api\Data\InquiryInterface. E.g:

<preference for="Mage2\Inquiry\Api\Data\InquiryInterface" type="Mage2\Inquiry\Model\Inquiry"/>

In Mage2\Inquiry\Model\Inquiry, you will need to implement that interface

class Inquiry implements \Mage2\Inquiry\Api\Data\InquiryInterface
{
    // content
}

After that, re-run the bin/magento setup:upgrade to clear all generated data and cache.

P/s: I also notice this in the __constructor()

$this->inquiryFactory = $inquiryFactory
            ?: \Magento\Framework\App\ObjectManager::getInstance()->get(InquiryFactory::class);
$this->inquiryRepository = $inquiryRepository
            ?: \Magento\Framework\App\ObjectManager::getInstance()->get(InquiryRepositoryInterface::class);

Is there any idea why ObjectManager used here? ObjectManager is the rival of DependencyInjection

Good luck!

Related Topic