0

The answer linked here mentioned (in the comments more specifically) that I am supposed to be able to get the Id from the repository/resource), it also more importantly confirmed that $model->save() is deprecated, and Repository to be used:

I implemented a Repository before this, and already had a working insert/update into the database.

The save() function is for a Repository implementation:

(Data for the Interface):

`order_history_id PRIMARY KEY`
`user_id`
`sales_order_id`

sales_order_id 19830 - The current sales order id
user_id 22           - A custom 'assigned user/sales/dispatch' ID

class AssignedOrderCommentHistoryRepository implements AssignedOrderCommentHistoryRepositoryInterface
    
    public function save(
        ..\AssignedOrderCommentHistoryInterface $user
    ) {

        $data = $user->getData();
        /** Remove primary id from array if this is a new row */
        if ($user->isNewRow()) {
            $data = $user->dataToArray();
        }
        /** **Model**\AssignedOrderCommentHistory $userModel **/
        $userModel = $this->assignedOrderCommentHistoryFactory->create()->setData($data);

        try {
           /** This is where I am saving (insert/update) successfully to database ... 
               How do I get the ID from here....  

               $inserted = $this->resource->save($userModel); 
               Returns type : '**Model\ResourceModel**\AssignedOrderCommentHistory' 
               which _does not have any getData()_ or there appears no 'primary id data returned'
           **/
           
           $this->resource->save($userModel);
}
/*** Try/catch trimmed */
        return $userModel->getDataModel();

I need the PRIMARY KEY order_history_id ID inserted for use in another data table, to store the related data.

Am I to implement my own SELECT * from table LIMIT 1 statement to find the 'last inserted row'? Would this even be reasonable to assume that I will get the correct ID with multiple inserts at the 'same time'?

I tried to look at some other examples, but most examples just show how to 'insert/update', which is what I already have correct.

5
  • did you ever find the solution to this problem. i have the same issue
    – theSeeker
    Mar 24 at 9:46
  • Hi, I have looked at my code just now, I will try to write an answer regarding the issue soon. Mar 24 at 14:22
  • @theSeeker I apologise for the long answer, as this was months ago, I cannot really remove much as I feel most is relevant to getting you a working save() on Repositories. Mar 24 at 15:11
  • @theSeeker Did the answer I provided help you? Mar 27 at 9:39
  • Hey @CvRChameleon , i will have a look at your answer. i will also provide a quick solution that I found to get the Id
    – theSeeker
    Mar 28 at 10:20

1 Answer 1

0

I have found a solution for the use of save() in a Repository, and I am trying to answer as @theSeeker also need a similar solution.

I created this around 7 months ago, and can't remember everything I have done, so the answer shows alot of code, but is relevant to a working repository, especially to save() when you have custom non-default primary ID.

Relevant code

  1. Your Resource (Database collection) should override the protected _idFieldName to the custom column primary id
class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{

    /**
     * @var string
     */
    protected $_idFieldName = DbHelper::FIELD_ORDERS_COMMENT_HISTORY_ORDER_HISTORY_ID;
  1. Save function inside Repository class. (Rest of the Repository code truncated)
    /**
     * {@inheritdoc}
     */
    public function save(
        \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryInterface $user
    ) {
        /* if (empty($user->getStoreId())) {
            $storeId = $this->storeManager->getStore()->getId();
            $user->setStoreId($storeId);
        } */

        /**
         * Not sure what these extensibleDataObjectConvertor is supposed to do, but I doubt it works
         * correctly, even sure in /Model/UserRepository and /Model/UserTypeRepository.
         * Same code taken from online resources.
         */
        // $data = $this->extensibleDataObjectConverter->toNestedArray(
        //     $user,
        //     [],
        //     \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryInterface::class
        // );

        $data = $user->getData();
        /** Remove primary id from array if this is a new row */
        if ($user->isNewRow()) {
            $data = $user->dataToArray();
        }
        $userModel = $this->assignedOrderCommentHistoryFactory->create()->setData($data);

        try {
            $this->resource->save($userModel);
        } catch (AlreadyExistsException $exExist) {
            throw new CouldNotSaveException(
                __(
                    'Could not save the assigned details: %1',
                    $exExist->getMessage()
                )
            );
        } catch (\Exception $exception) {
            throw new CouldNotSaveException(__(
                'Could not save the assigned details: %1',
                $exception->getMessage()
            ));
        }
        return $userModel->getDataModel();
    }
  1. Data Model - You can then create an Interface for your Data Model:
interface BaseExtensibleDataInterface extends \Magento\Framework\Api\ExtensibleDataInterface
{
    /**
     * Return true if the object has data
     *
     * @return boolean
     */
    public function hasData();

    /**
     * Return if this is a new row (no existing data)
     *
     * @return boolean
     */
    public function isNewRow();

    /**
     * Set that this is a new row (no existing data)
     * @return this
     */
    public function setIsNewRow();

    /**
     * Return if this is an update row (not a new row)
     *
     * @return boolean
     */
    public function isUpdateRow();

    /**
     * Set that this is an update row (not a new row)
     * @return this
     */
    public function setIsUpdateRow();

    /**
     * Get All data or data for a specific key when specified
     *
     * @param string $key If Empty will return all data
     * @return array
     */
    public function getData($key = "");

    /**
     * Convert object->getData() to Array
     *
     * @return array
     */
    public function dataToArray(bool $ignorePrimaryId = true);

    /**
     * Set data from array of data
     *
     * @param array $data
     * @return void
     */
    public function setDataFromArray(array $data);

    /**
     * Set data from AbstractModel model
     *
     * @param \Magento\Framework\Model\AbstractModel $model
     * @return void
     */
    public function setDataFromModel(\Magento\Framework\Model\AbstractModel $model);
}
  1. I then created an abstract object implementing the interface as I used it for several implementations.

NOTE: I am truncating the class, just adding the code I feel is relevant to the issue.

abstract class AbstractApiInterfacedExtensibleObject
extends \Magento\Framework\Api\AbstractExtensibleObject
implements BaseExtensibleDataInterface
{
    protected $_isNewRow;

    /**
     * Return true if the object has data
     *
     * @return boolean
     */
    public function hasData()
    {
        return !empty($this->getData());
    }

    /**
     * Return if this is a new row (no existing data)
     *
     * @return boolean
     */
    public function isNewRow()
    {
        return $this->_isNewRow;
    }

    /**
     * Set that this is a new row (no existing data)
     * @return this
     */
    public function setIsNewRow()
    {
        $this->_isNewRow = true;
    }

    /**
     * Return if this is an update row (not a new row)
     *
     * @return boolean
     */
    public function isUpdateRow()
    {
        return !$this->isNewRow();
    }

    /**
     * Set that this is an update row (not a new row)
     *
     * @return this
     */
    public function setIsUpdateRow()
    {
        $this->_isNewRow = false;
    }

    /**
     * Get All data or data for a specific key when specified
     *
     * @param string $key If Empty will return all data
     * @return array
     */
    public function getData($key = "")
    {
        if (!is_null($this->_data)) {
            if (!empty($key) && array_key_exists($key, $this->_data)) {
                return $this->_data[$key];
            }
            return $this->_data;
        }
        return array();
    }

    /**
     * Convert object->getData() to Array
     *
     * @return array
     */
    public function dataToArray(bool $ignorePrimaryId = true)
    {
        if ($ignorePrimaryId) {
            $data = $this->getData();
            if (array_key_exists(static::PRIMARY_ID, $data)) {
                unset($data[static::PRIMARY_ID]);
            }
            return $data;
        }
        return $this->getData();
    }

    /**
     * Set data from array of data
     *
     * @param array $data
     * @return this
     */
    public function setDataFromArray(array $data)
    {
        foreach ($data as $key => $value) {
            $this->_data[$key] = $value;
        }
        return $this;
    }

    /**
     * Set data from AbstractModel model
     *
     * @param \Magento\Framework\Model\AbstractModel $model
     * @return this
     */
    public function setDataFromModel(\Magento\Framework\Model\AbstractModel $model)
    {
        return $this->setDataFromArray($model->getData());
    }
}
  1. Then finally the actual Data Model
class AssignedOrderCommentHistoryDetail extends AbstractApiInterfacedExtensibleObject implements AssignedOrderCommentHistoryDetailInterface
{

    /**
     * Get PRIMARY_ID
     * @return string|null
     */
    public function getPrimaryId()
    {
        return $this->_get(static::PRIMARY_ID);
    }

    /**
     * Set PRIMARY_ID
     * @param string $primaryId
     * @return \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryDetailInterface
     */
    public function setPrimaryId($primaryId)
    {
        return $this->setData(static::PRIMARY_ID, $primaryId);
    }

    /**
     * Get RELATED_ORDER_HISTORY_ID
     * @return string|null
     */
    public function getRelatedOrderHistoryId()
    {
        return $this->_get(static::RELATED_ORDER_HISTORY_ID);
    }

    /**
     * Set RELATED_ORDER_HISTORY_ID
     * @param string $relatedOrderHistoryId
     * @return \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryDetailInterface
     */
    public function setRelatedOrderHistoryId($relatedOrderHistoryId)
    {
        return $this->setData(static::RELATED_ORDER_HISTORY_ID, $relatedOrderHistoryId);
    }

    /**
     * Get ASSIGNED_SALES_ORDER_HISTORY_COMMENT_ID
     * @return string|null
     */
    public function getAssignedSalesOrderHistoryCommentId()
    {
        return $this->_get(static::ASSIGNED_SALES_ORDER_HISTORY_COMMENT_ID);
    }

    /**
     * Set ASSIGNED_SALES_ORDER_HISTORY_COMMENT_ID
     * @param string $commentId
     * @return \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryDetailInterface
     */
    public function setAssignedSalesOrderHistoryCommentId($commentId)
    {
        return $this->setData(static::ASSIGNED_SALES_ORDER_HISTORY_COMMENT_ID, $commentId);
    }

    /**
     * Get ASSIGNED_USER_USER_ID
     * @return string|null
     */
    public function getAssignedUserId()
    {
        return $this->_get(static::ASSIGNED_USER_USER_ID);
    }

    /**
     * Set ASSIGNED_USER_USER_ID
     * @param string $userId
     * @return \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryDetailInterface
     */
    public function setAssignedUserId($userId)
    {
        return $this->setData(static::ASSIGNED_USER_USER_ID, $userId);
    }

    /**
     * Retrieve existing extension attributes object or create a new one.
     * @return \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryDetailExtensionInterface|null
     */
    public function getExtensionAttributes()
    {
        return $this->_getExtensionAttributes();
    }

    /**
     * Set an extension attributes object.
     * @param \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryDetailExtensionInterface $extensionAttributes
     * @return $this
     */
    public function setExtensionAttributes(
        \Vendor\ModuleName\Api\Data\AssignedOrderCommentHistoryDetailExtensionInterface $extensionAttributes
    ) {
        return $this->_setExtensionAttributes($extensionAttributes);
    }

Explanation

Have a look at the save() function in the Repository.

$data = $user->getData();

  • The custom getData() filters information which I don't need and formats the array in the associative format Magento 2 expects for 'Data Models with Repositories'.
if ($user->isNewRow()) {
   $data = $user->dataToArray();
}
  • I call isNewRow() to find if the row is new (you can use setIsNewRow() somewhere to set it as new if you can't determine automatically)
  • The dataToArray() then removes the primary key when new row or not.

$userModel = $this->assignedOrderCommentHistoryFactory->create()->setData($data);

  • Create the Factory AssignedOrderCommentHistoryFactory of the Model AssignedOrderCommentHistory that you set in the constructor of the Repository (the name ends with Factory, with the same namespace as your Class, and Magento 2 creates the class automatically when you run bin/magento setup:di:compile - for more information research further about Magento 2 Factories).

$this->resource->save($userModel);

  • Then you can save to the Magento 2 resource, this will then create a new row or update the model if it exists in the database $this->resource->save($userModel)

return $userModel->getDataModel();

  • Finally: Make sure you return a different format Data Model inside the save() function which Magento 2 expects.

Summary

There is no summary, as this has been over 7 months ago, I cannot remember everything done here, I do remember the main things that had me struggling, and the explanation I gave above covers most.

TLDR

  • Do I need a custom implementation for a Repository save when using a non-default primary ID name?

  • Yes, absolutely yes! Override the Collection primary id field, implement a custom getData() and dataToArray() to ensure the custom field is added / removed for new rows/update rows.

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.