Is there ever a reason to prefer $model->load() over service contracts?
The reason to use ProductRepository
's get
/getById
instead of a ProductFatory's load()
method, is because the former is of a higher level than the latter.
A ProductRepository
- just like a ProductFactory
- might return a Product
model, but that is not what M2 wants you to consider. That's not what \Magento\Catalog\Api\ProductRepositoryInterface::getById()
's doc block says. It says @return \Magento\Catalog\Api\Data\ProductInterface
, which is an interface a Product model is implementing.
SO, you should use the API layer whenever possible, because:
Api/Data
layer is used in the Web Api, as well- models can - and probably will - be refactored at some point;
Api/Data/Product
will not. - To get a product in your classes, you need to inject either a concrete factory (
ProductFactory
) or an interface (ProductRepository
). I don't think you want your module to rely on anything but an interface. Hence I disagree with this type of injection.
I consider it to be just another tiny abstraction layer above models, to cater for the Web API (REST, SOAP etc.).
Quoting this answer:
Hopefully, you will love service contracts when your custom module will not be broken after the next releases of Magento 2 (of course if you do not bypass service contracts and use models/collections/resource models directly). And when you start consuming/exposing Magento 2 web API, which is now based on the same service contracts. So you have to make changes only in one place (e.g. via plugin) and they will be applied everywhere. This was impossible in Magento 1.
To me, there is no reason to use the load
method over the getById
/ get
method.
I don't say that I'm right but here's how I see things.
Ok so here's the getById
method (get
method is similar but uses the sku instead of the id):
public function getById($productId, $editMode = false, $storeId = null, $forceReload = false)
{
$cacheKey = $this->getCacheKey(func_get_args());
if (!isset($this->instancesById[$productId][$cacheKey]) || $forceReload) {
$product = $this->productFactory->create();
if ($editMode) {
$product->setData('_edit_mode', true);
}
if ($storeId !== null) {
$product->setData('store_id', $storeId);
}
$product->load($productId);
if (!$product->getId()) {
throw new NoSuchEntityException(__('Requested product doesn\'t exist'));
}
$this->instancesById[$productId][$cacheKey] = $product;
$this->instances[$product->getSku()][$cacheKey] = $product;
}
return $this->instancesById[$productId][$cacheKey];
}
As you can notice the code you pasted:
$productFactory->create()->load($id);
Is part of this function.
However, the extra condition uses cached instances to avoid an extra reload in case you have previously used the getById
or the get
method for the same id (or sku in case of the get
method).
You may think that a good reason to use load
could be to avoid using those cached instances (in which case could that be a good reason ? that I don't know) but the getById
and the get
methods have a $forceReload
parameter that can be set to true to avoid using those cache instances.
That's why to me, there's no good reason to use load
method over getById
or get
methods.
Please understand the difference between repositories and collections.
In your example, if using repositories, you will get an array of Magento\Catalog\Api\Data\ProductInterface
that is different from getting a collection of Magento\Catalog\Model\Product
.
Repositories and data interface give you an high interface level that should be guaranteed as compatible in future relases. This is why it is the suggested approach.
Hope it helps.