How to save an EAV entity from controller?
-
03-10-2020 - |
Question
I'm trying to build a custom module that contains an EAV entity in Magento 2 for learning purposes.
I have troubles performing a proper save from an admin controller.
I'm trying to avoid code like:
$data = get data from post here;
$myObj->addData($data)->save();
Because the save method is deprecated and because I'm trying to work with interfaces instead of their implementations.
For a flat entity I could do this:
$entity = either get it from a repository or via factory;
$data = get data from post
$this->dataObjectHelper->populateWithArray($entity, $data, EntityInterface::class);
Where dataObjectHelper
is an instance of \Magento\Framework\Api\DataObjectHelper
that reads the setters of the interface passed as the 3rd parameter and maps the corresponding to the methods from the $data
array to my entity.
So if $data
looks like this:
$data = [
'title'=>'Some title',
'description' => 'Some description'
]
will just call $entity->setTitle('Some title')->setDescription('Some description')
.
But I cannot do that for the EAV entities because my entity interface will contain only the system attributes and not the custom ones.
I need to get the data from POST and pass it to the $entity
instance and then call $entityRepository->save($entity)
but I don't want to lose any custom attributes.
How can I proceed in this case?
I looked in the core and for products and categories the controllers still call $entity->save()
which is not OK.
Solution
So, from what I understood, Magento 2 is slowly switching to the EntityManager which is used to extract and hydrate the entities.
Populating the data
To populate the data, you need to use the hydrator so \Magento\Framework\EntityManager\Hydrator
:
$entity = $this->hydrator->hydrate($entity, $dataArray);
Saving the entity
That's already halfway implemented in 2.1. Let's look at the product resource model save()
method:
public function save(\Magento\Framework\Model\AbstractModel $object)
{
$this->getEntityManager()->save($object);
return $this;
}
That is the right way of doing it. The only thing not implemented yet is that it's still trigerred via the save()
call because the deprecated method still calls $this->_getResource()->save($this);
OTHER TIPS
How about populating your data as usual, but using the resource to perform the save.
At least that's how I currently work around the deprecation issue.