2

I create a custom entity and repository. All work well, but the POST API route does not create new entities. But if I call the PUT API route to change a property, it works well. Why my custom repository doesn't create new entities?

webapi.xml

<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
 <route url="/V1/shipment_methods" method="GET">
 <service class="MyVendorName\MyModuleName\Api\ShipmentMethodRepositoryInterface" method="getList"/>
 <resources>
 <resource ref="anonymous"/>
 </resources>
 </route>
 <route url="/V1/shipment_methods/:code" method="GET">
 <service class="MyVendorName\MyModuleName\Api\ShipmentMethodRepositoryInterface" method="getByCode"/>
 <resources>
 <resource ref="MyVendorName_MyModuleName::shipment_method"/>
 </resources>
 </route>
 <route url="/V1/shipment_methods" method="POST">
 <service class="MyVendorName\MyModuleName\Api\ShipmentMethodRepositoryInterface" method="save"/>
 <resources>
 <resource ref="MyVendorName_MyModuleName::shipment_method_save"/>
 </resources>
 </route>
 <route url="/V1/shipment_methods/:code" method="PUT">
 <service class="MyVendorName\MyModuleName\Api\ShipmentMethodRepositoryInterface" method="save"/>
 <resources>
 <resource ref="MyVendorName_MyModuleName::shipment_method_save"/>
 </resources>
 </route>
 <route url="/V1/shipment_methods" method="DELETE">
 <service class="MyVendorName\MyModuleName\Api\ShipmentMethodRepositoryInterface" method="delete"/>
 <resources>
 <resource ref="MyVendorName_MyModuleName::shipment_method_delete"/>
 </resources>
 </route>
 <route url="/V1/shipment_methods/:code" method="DELETE">
 <service class="MyVendorName\MyModuleName\Api\ShipmentMethodRepositoryInterface" method="deleteByCode"/>
 <resources>
 <resource ref="MyVendorName_MyModuleName::shipment_method_delete"/>
 </resources>
 </route>
</routes>

ShipmentMethodRepository

<?php
declare(strict_types=1);
namespace MyVendorName\MyModuleName\Model;
use MyVendorName\MyModuleName\Api\Data\ShipmentMethodInterface;
use MyVendorName\MyModuleName\Api\Data\ShipmentMethodSearchResultsInterface;
use MyVendorName\MyModuleName\Api\ShipmentMethodRepositoryInterface;
use MyVendorName\MyModuleName\Model\ResourceModel\ShipmentMethod as ShipmentMethodResourceModel;
use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Exception\CouldNotDeleteException;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\NoSuchEntityException;
class ShipmentMethodRepository implements ShipmentMethodRepositoryInterface
{
 /**
 * @var ShipmentMethodFactory
 */
 private $shipmentMethodFactory;
 /**
 * @var ShipmentMethodResourceModel
 */
 private $shipmentMethodResourceModel;
 /**
 * ShipmentMethodRepository constructor.
 * @param ShipmentMethodFactory $shipmentMethodFactory
 * @param ShipmentMethodResourceModel $shipmentMethodResourceModel
 */
 public function __construct(
 ShipmentMethodFactory $shipmentMethodFactory,
 ShipmentMethodResourceModel $shipmentMethodResourceModel
 ) {
 $this->shipmentMethodFactory = $shipmentMethodFactory;
 $this->shipmentMethodResourceModel = $shipmentMethodResourceModel;
 }
 /**
 * Retrieve shipment methods which match a specified criteria
 * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
 * @return \MyVendorName\MyModuleName\Api\Data\ShipmentMethodSearchResultsInterface
 */
 public function getList(SearchCriteriaInterface $searchCriteria): ShipmentMethodSearchResultsInterface
 {
 // TODO: Implement getList() method.
 }
 /**
 * Get shipment method by code
 * @param string $code
 * @return \MyVendorName\MyModuleName\Api\Data\ShipmentMethodInterface
 * @throws \Magento\Framework\Exception\NoSuchEntityException
 */
 public function getByCode(string $code): ShipmentMethodInterface
 {
 $shipmentMethod = $this->shipmentMethodFactory->create();
 $this->shipmentMethodResourceModel->load($shipmentMethod, $code);
 if (!$shipmentMethod->getCode()) {
 throw new NoSuchEntityException(__('Shipment method with code %1 does not exist.', $code));
 }
 return $shipmentMethod;
 }
 /**
 * Create or update a shipment method
 * @param \MyVendorName\MyModuleName\Api\Data\ShipmentMethodInterface $shipmentMethod
 * @return \MyVendorName\MyModuleName\Api\Data\ShipmentMethodInterface
 * @throws \Magento\Framework\Exception\CouldNotSaveException
 */
 public function save(ShipmentMethodInterface $shipmentMethod): ShipmentMethodInterface
 {
 try {
 $this->shipmentMethodResourceModel->save($shipmentMethod);
 } catch (\Exception $e) {
 throw new CouldNotSaveException(__($e->getMessage()));
 }
 return $shipmentMethod;
 }
 /**
 * Delete shipment method
 * @param \MyVendorName\MyModuleName\Api\Data\ShipmentMethodInterface $shipmentMethod
 * @return bool
 * @throws \Magento\Framework\Exception\CouldNotDeleteException
 */
 public function delete(ShipmentMethodInterface $shipmentMethod): bool
 {
 try {
 $this->shipmentMethodResourceModel->delete($shipmentMethod);
 } catch (\Exception $e) {
 throw new CouldNotDeleteException(__($e->getMessage()));
 }
 return true;
 }
 /**
 * Delete shipment method by code
 * @param string $code
 * @return bool
 * @throws \Magento\Framework\Exception\NoSuchEntityException
 * @throws \Magento\Framework\Exception\CouldNotDeleteException
 */
 public function deleteByCode(string $code): bool
 {
 return $this->delete($this->getByCode($code));
 }
}

di.xml

<preference for="MyVendorName\MyModuleName\Api\Data\ShipmentMethodInterface" type="MyVendorName\MyModuleName\Model\ShipmentMethod"/>
<preference for="MyVendorName\MyModuleName\Api\ShipmentMethodRepositoryInterface" type="MyVendorName\MyModuleName\Model\ShipmentMethodRepository"/>

Model\ShipmentMethod

<?php
declare(strict_types=1);
namespace MyVendorName\MyModuleName\Model;
use MyVendorName\MyModuleName\Api\Data\ShipmentMethodInterface;
use MyVendorName\MyModuleName\Model\ResourceModel\ShipmentMethod as ShipmentMethodResourceModel;
use Magento\Framework\Model\AbstractModel;
class ShipmentMethod extends AbstractModel implements ShipmentMethodInterface
{
 /**
 * {@inheritDoc}
 */
 protected function _construct(): void
 {
 $this->_init(ShipmentMethodResourceModel::class);
 }
 /**
 * {@inheritDoc}
 */
 public function getCode(): string
 {
 return (string)$this->getData(self::CODE);
 }
 /**
 * {@inheritDoc}
 */
 public function setCode(string $code): ShipmentMethodInterface
 {
 $this->setData(self::CODE, $code);
 return $this;
 }
 /**
 * {@inheritDoc}
 */
 public function getDescription(): string
 {
 return (string)$this->getData(self::DESCRIPTION);
 }
 /**
 * {@inheritDoc}
 */
 public function setDescription(string $description): ShipmentMethodInterface
 {
 $this->setData(self::DESCRIPTION, $description);
 return $this;
 }
 /**
 * {@inheritDoc}
 */
 public function getCourierCode(): string
 {
 return (string)$this->getData(self::COURIER_CODE);
 }
 /**
 * {@inheritDoc}
 */
 public function setCourierCode(string $courierCode): ShipmentMethodInterface
 {
 $this->setData(self::COURIER_CODE, $courierCode);
 return $this;
 }
 /**
 * {@inheritDoc}
 */
 public function getServiceCode(): string
 {
 return (string)$this->getData(self::SERVICE_CODE);
 }
 /**
 * {@inheritDoc}
 */
 public function setServiceCode(string $serviceCode): ShipmentMethodInterface
 {
 $this->setData(self::SERVICE_CODE, $serviceCode);
 return $this;
 }
 /**
 * {@inheritDoc}
 */
 public function getIsExpress(): bool
 {
 return (bool)$this->getData(self::IS_EXPRESS);
 }
 /**
 * {@inheritDoc}
 */
 public function setIsExpress(bool $isExpress): ShipmentMethodInterface
 {
 $this->setData(self::IS_EXPRESS, $isExpress);
 return $this;
 }
 /**
 * {@inheritDoc}
 */
 public function getTiming(): string
 {
 return (string)$this->getData(self::TIMING);
 }
 /**
 * {@inheritDoc}
 */
 public function setTiming(string $timing): ShipmentMethodInterface
 {
 $this->setData(self::TIMING, $timing);
 return $this;
 }
}

Model\ResourceModel\ShipmentMethod

<?php
declare(strict_types=1);
namespace MyVendorName\MyModuleName\Shipment\Model\ResourceModel;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
class ShipmentMethod extends AbstractDb
{
 public const TABLE_NAME = 'my_shipment_method';
 /**
 * {@inheritDoc}
 */
 protected function _construct(): void
 {
 $this->_init(self::TABLE_NAME, 'code');
 }
}
asked Jun 28, 2019 at 20:07
8
  • Are you getting an error in the response of the rest api request? What is the result of making that call? Commented Jun 29, 2019 at 2:28
  • @floorz I receive the ShipmentMethod object that I return after try-catch. I checked the logs, and there aren't any errors Commented Jun 29, 2019 at 6:46
  • What if you remove that php return type on the save method? That's the only thing that stands out here without seeing more code. Commented Jun 29, 2019 at 7:17
  • That or capture the return result of the resource model save and return that instead. Commented Jun 29, 2019 at 7:19
  • 1
    Ohhhh interesting! Nice find! Happy coding :) Commented Jun 29, 2019 at 17:36

1 Answer 1

3

I found the solution through this post how-set-resource-model-for-not-primary-ai :). In nutshell, because my primary key is not auto-increment, the resource model fails the save method for new entities. To solve the problem you should set protected $_isPkAutoIncrement = false; inside your resource model class

answered Jun 29, 2019 at 8:54

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.