355 private $filterCustomAttribute;
401 \
Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
407 \
Magento\Catalog\Model\
Product\Configuration\Item\OptionFactory $itemOptionFactory,
408 \
Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory $stockItemFactory,
409 \
Magento\Catalog\Model\
Product\OptionFactory $catalogProductOptionFactory,
410 \
Magento\Catalog\Model\
Product\Visibility $catalogProductVisibility,
413 Product\Type $catalogProductType,
418 \
Magento\Framework\Data\CollectionFactory $collectionFactory,
421 \
Magento\Catalog\Model\Indexer\
Product\Flat\Processor $productFlatIndexerProcessor,
422 \
Magento\Catalog\Model\Indexer\
Product\Price\Processor $productPriceIndexerProcessor,
423 \
Magento\Catalog\Model\Indexer\
Product\Eav\Processor $productEavIndexerProcessor,
438 $this->_itemOptionFactory = $itemOptionFactory;
439 $this->_stockItemFactory = $stockItemFactory;
440 $this->optionFactory = $catalogProductOptionFactory;
441 $this->_catalogProductVisibility = $catalogProductVisibility;
442 $this->_catalogProductStatus = $catalogProductStatus;
443 $this->_catalogProductMediaConfig = $catalogProductMediaConfig;
444 $this->_catalogProductType = $catalogProductType;
446 $this->_catalogProduct = $catalogProduct;
447 $this->_collectionFactory = $collectionFactory;
448 $this->_urlModel =
$url;
452 $this->_productFlatIndexerProcessor = $productFlatIndexerProcessor;
453 $this->_productPriceIndexerProcessor = $productPriceIndexerProcessor;
454 $this->_productEavIndexerProcessor = $productEavIndexerProcessor;
475 $this->filterCustomAttribute = $filterCustomAttribute
499 return parent::_getResource();
511 if ($this->customAttributesCodes ===
null) {
512 $this->customAttributesCodes = array_diff(
514 $this->filterCustomAttribute->execute(
515 $this->eavConfig->getEntityAttributes(
535 if ($this->
hasData(self::STORE_ID)) {
536 return $this->
getData(self::STORE_ID);
538 return $this->_storeManager->getStore()->getId();
560 $this->_eventManager->dispatch($this->_eventPrefix .
'_validate_before', $this->
_getEventData());
562 $this->_eventManager->dispatch($this->_eventPrefix .
'_validate_after', $this->
_getEventData());
586 if ($this->_calculatePrice || !$this->
getData(self::PRICE)) {
589 return $this->
getData(self::PRICE);
603 return $this->
_getData(self::VISIBILITY);
613 return $this->
_getData(self::ATTRIBUTE_SET_ID);
623 return $this->
_getData(self::CREATED_AT);
633 return $this->
_getData(self::UPDATED_AT);
645 $this->_calculatePrice = $calculate;
655 return $this->
_getData(self::TYPE_ID);
668 return $status !==
null ?
$status : \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED;
680 if ($this->_typeInstance ===
null) {
681 $this->_typeInstance = $this->_catalogProductType->factory($this);
694 $this->_typeInstance = $instance;
726 $category = $this->_registry->registry(
'current_category');
755 if (!$this->
hasData(
'category_ids')) {
762 $this->
setData(
'category_ids', $ids);
768 return (array) $this->
_getData(
'category_ids');
778 if ($this->categoryCollection ===
null || $this->
getId() != $this->_productIdCached) {
781 $this->_productIdCached = $this->
getId();
805 if (!$this->hasWebsiteIds()) {
807 $this->setWebsiteIds($ids);
809 return $this->
getData(
'website_ids');
819 if (!$this->hasStoreIds()) {
823 $websiteStores = $this->_storeManager->getWebsite(
$websiteId)->getStoreIds();
824 $storeIds = array_merge($storeIds, $websiteStores);
827 $this->setStoreIds($storeIds);
829 return $this->
getData(
'store_ids');
844 $productAttributes = $this->
getTypeInstance()->getSetAttributes($this);
869 $this->setTypeHasOptions(
false);
870 $this->setTypeHasRequiredOptions(
false);
871 $this->setHasOptions(
false);
872 $this->setRequiredOptions(
false);
877 $hasRequiredOptions =
false;
884 $this->
canAffectOptions($this->_canAffectOptions && $this->getCanSaveCustomOptions());
885 if ($this->getCanSaveCustomOptions()) {
888 $this->setIsCustomOptionChanged(
true);
890 if (
$option instanceof \
Magento\Catalog\Api\Data\ProductCustomOptionInterface) {
893 if (!isset(
$option[
'is_delete']) ||
$option[
'is_delete'] !=
'1') {
896 if (
$option[
'is_require'] ==
'1') {
897 $hasRequiredOptions =
true;
908 if ($hasOptions || (
bool)$this->getTypeHasOptions()) {
909 $this->setHasOptions(
true);
910 if ($hasRequiredOptions || (
bool)$this->getTypeHasRequiredOptions()) {
911 $this->setRequiredOptions(
true);
913 $this->setRequiredOptions(
false);
916 $this->setHasOptions(
false);
917 $this->setRequiredOptions(
false);
924 parent::beforeSave();
938 $this->_canAffectOptions = (bool)
$value;
954 $this->setForceReindexEavRequired(
true);
957 $this->
_getResource()->addCommitCallback([$this,
'priceReindexCallback']);
958 $this->
_getResource()->addCommitCallback([$this,
'eavReindexCallback']);
962 $this->
_getResource()->addCommitCallback([$this,
'reindex']);
976 if ($this->
getData(
'qty') != $qty) {
1000 if ($this->
isObjectNew() || $this->_catalogProduct->isDataForPriceIndexerWasChanged($this)) {
1001 $this->_productPriceIndexerProcessor->reindexRow($this->
getEntityId());
1013 $this->_productEavIndexerProcessor->reindexRow($this->
getEntityId());
1024 foreach (array_keys($this->
getData()) as $field) {
1039 if ($this->_catalogProduct->isDataForProductCategoryIndexerWasChanged($this) || $this->
isDeleted()) {
1040 $productCategoryIndexer = $this->indexerRegistry->get(Indexer\
Product\Category::INDEXER_ID);
1041 if (!$productCategoryIndexer->isScheduled()) {
1042 $productCategoryIndexer->reindexRow($this->
getId());
1045 $this->_productFlatIndexerProcessor->reindexRow($this->
getEntityId());
1059 return parent::beforeDelete();
1070 $this->_productPriceIndexerProcessor->reindexRow($this->
getId());
1071 parent::afterDeleteCommit();
1081 if (!$this->
hasData(self::STATUS)) {
1084 parent::_afterLoad();
1095 $this->_cacheManager->clean(
'catalog_product_' . $this->
getId());
1106 return $this->_catalogProductType->priceFactory($this->
getTypeId());
1116 if (!$this->_priceInfo) {
1117 $this->_priceInfo = $this->_catalogProductType->getPriceInfo($this);
1191 $this->_data[
'final_price'] =
$price;
1203 if ($this->_calculatePrice || $this->
_getData(
'final_price') ===
null) {
1206 return $this->
_getData(
'final_price');
1217 return $this->
_getData(
'calculated_final_price');
1227 return max($this->
_getData(
'minimal_price'), 0);
1237 return $this->
_getData(
'special_price');
1247 return $this->
_getData(
'special_from_date');
1257 return $this->
_getData(
'special_to_date');
1267 if (!$this->hasRelatedProducts()) {
1275 return $this->
getData(
'related_products');
1285 if (!$this->hasRelatedProductIds()) {
1290 $this->setRelatedProductIds($ids);
1292 return $this->
getData(
'related_product_ids');
1329 if (!$this->hasUpSellProducts()) {
1336 return $this->
getData(
'up_sell_products');
1346 if (!$this->hasUpSellProductIds()) {
1351 $this->setUpSellProductIds($ids);
1353 return $this->
getData(
'up_sell_product_ids');
1390 if (!$this->hasCrossSellProducts()) {
1397 return $this->
getData(
'cross_sell_products');
1407 if (!$this->hasCrossSellProductIds()) {
1412 $this->setCrossSellProductIds($ids);
1414 return $this->
getData(
'cross_sell_product_ids');
1451 if ($this->_links ===
null) {
1452 $this->_links = $this->getLinkRepository()->getList($this);
1466 $this->
setData(
'ignore_links_flag',
true);
1468 $this->
setData(
'ignore_links_flag',
false);
1481 if (!$this->hasMediaAttributes()) {
1482 $mediaAttributes = [];
1484 if (
$attribute->getFrontend()->getInputType() ==
'media_image') {
1488 $this->setMediaAttributes($mediaAttributes);
1490 return $this->
getData(
'media_attributes');
1500 $mediaAttributeCodes = $this->_catalogProductMediaConfig->getMediaAttributeCodes();
1501 $mediaAttributeValues = [];
1505 return $mediaAttributeValues;
1516 if (!$this->
hasData(
'media_gallery_images')) {
1517 $this->
setData(
'media_gallery_images', $this->_collectionFactory->create());
1519 if (!$this->
getData(
'media_gallery_images')->count() && is_array($this->getMediaGallery(
'images'))) {
1520 $images = $this->
getData(
'media_gallery_images');
1521 foreach ($this->getMediaGallery(
'images') as
$image) {
1522 if (!empty(
$image[
'disabled'])
1523 || !empty(
$image[
'removed'])
1524 || empty(
$image[
'value_id'])
1525 || $images->getItemById(
$image[
'value_id']) != null
1534 $this->
setData(
'media_gallery_images', $images);
1537 return $this->
getData(
'media_gallery_images');
1551 || !(
$attributes[
'media_gallery'] instanceof \
Magento\Eav\Model\Entity\Attribute\AbstractAttribute)
1572 $this->getMediaGalleryProcessor()->addImage(
1601 return $this->_catalogProductStatus->getVisibleStatusIds();
1611 return $this->_catalogProductStatus->getVisibleStatusIds();
1631 return $this->_catalogProductVisibility->getVisibleInSiteIds();
1662 $this->_isDuplicable = (bool)
$value;
1673 if ($this->_catalogProduct->getSkipSaleableCheck()) {
1677 || $this->isStockStatusChanged()) {
1681 if ($this->
hasData(
'salable')) {
1682 return $this->
getData(
'salable');
1684 $this->_eventManager->dispatch(
'catalog_product_is_salable_before', [
'product' => $this]);
1688 $object = new \Magento\Framework\DataObject([
'product' => $this,
'is_salable' => $salable]);
1689 $this->_eventManager->dispatch(
1690 'catalog_product_is_salable_after',
1691 [
'product' => $this,
'salable' => $object]
1693 $this->
setData(
'salable', $object->getIsSalable());
1694 return $this->
getData(
'salable');
1704 return $this->_catalogProduct->getSkipSaleableCheck() || $this->
getTypeInstance()->isSalable($this);
1716 if (method_exists($productType,
'getIsSalable')) {
1717 return $productType->getIsSalable($this);
1719 if ($this->
hasData(
'is_saleable')) {
1720 return $this->
getData(
'is_saleable');
1753 return $this->
getStatus() == \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED;
1791 return $this->
getUrlModel()->getProductUrl($this, $useSid);
1843 public function toArray(array $arrAttributes = [])
1845 $data = parent::toArray($arrAttributes);
1846 $stock = $this->getStockItem();
1850 unset(
$data[
'stock_item'][
'product']);
1862 if (isset(
$data[
'stock_item'])) {
1863 if ($this->moduleManager->isEnabled(
'Magento_CatalogInventory')) {
1864 $stockItem = $this->_stockItemFactory->create();
1865 $this->dataObjectHelper->populateWithArray(
1867 $data[
'stock_item'],
1868 \
Magento\CatalogInventory\Api\Data\StockItemInterface::class
1873 unset(
$data[
'stock_item']);
1886 return $this->
_getData(
'request_path');
1896 return $this->
_getData(
'gift_message_available');
1947 if (!isset($this->optionInstance)) {
1948 $this->optionInstance = $this->optionFactory->create();
1949 $this->optionInstance->setProduct($this);
1964 $option->setProduct($this);
1975 public function getOptionById(
$optionId)
2006 return $this->
getData(
'options');
2043 $option = $this->_itemOptionFactory->create()->addData(
2079 if (isset($this->_customOptions[
$code])) {
2080 return $this->_customOptions[
$code];
2092 if (count($this->_customOptions)) {
2107 return $this->
_getResource()->canBeShowInCategory($this, $categoryId);
2117 return $this->
_getResource()->getAvailableInCategories($this);
2127 return $this->
getResource()->getEntityType()->getDefaultAttributeSetId();
2151 $tags = parent::getCacheIdTags();
2152 $affectedCategoryIds = $this->getAffectedCategoryIds();
2153 if (!$affectedCategoryIds) {
2156 foreach ($affectedCategoryIds as $categoryId) {
2190 $options = new \Magento\Framework\DataObject();
2207 $options->addData($typeSpecificOptions);
2222 $preConfiguredValues = $this->
getData(
'preconfigured_values');
2223 if (!$preConfiguredValues) {
2224 $preConfiguredValues = new \Magento\Framework\DataObject();
2227 return $preConfiguredValues;
2255 $this->_clearOptionReferences();
2266 foreach ($this->_data as
$data) {
2267 if (is_object(
$data) && method_exists(
$data,
'reset') && is_callable([
$data,
'reset'])) {
2274 $this->_customOptions = [];
2275 $this->_canAffectOptions =
false;
2276 $this->_errors = [];
2286 protected function _clearOptionReferences()
2320 return $this->
getStatus() == \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED;
2331 return parent::getImage();
2341 $identities = [self::CACHE_TAG .
'_' . $this->
getId()];
2342 if ($this->getIsChangedCategories()) {
2343 foreach ($this->getAffectedCategoryIds() as $categoryId) {
2344 $identities[] = self::CACHE_PRODUCT_CATEGORY_TAG .
'_' . $categoryId;
2348 if (($this->
getOrigData(
'status') != $this->
getData(
'status')) || $this->isStockStatusChanged()) {
2350 $identities[] = self::CACHE_PRODUCT_CATEGORY_TAG .
'_' . $categoryId;
2357 return array_unique($identities);
2365 private function isStockStatusChanged()
2369 if ($extendedAttributes !==
null) {
2370 $stockItem = $extendedAttributes->getStockItem();
2375 && array_key_exists(
'is_in_stock',
$stockData)
2388 if ($this->_priceInfo) {
2389 $this->_priceInfo =
null;
2403 $hasToArray =
function (
$model) {
2404 return is_object(
$model) && method_exists(
$model,
'__toArray') && is_callable([
$model,
'__toArray']);
2407 if ($hasToArray(
$value)) {
2410 foreach (
$value as $nestedKey => $nestedValue) {
2411 if ($hasToArray($nestedValue)) {
2412 $value[$nestedKey] = $nestedValue->__toArray();
2426 public function toFlatArray()
2430 if (array_key_exists(
'custom_attributes', $dataArray) && !empty($dataArray[
'custom_attributes'])) {
2432 $customAttributes = $dataArray[
'custom_attributes'];
2433 unset($dataArray[
'custom_attributes']);
2434 foreach ($customAttributes as $attributeValue) {
2450 return $this->
setData(self::SKU, $sku);
2516 return $this->
setData(self::VISIBILITY, $visibility);
2527 return $this->
setData(self::CREATED_AT, $createdAt);
2538 return $this->
setData(self::UPDATED_AT, $updatedAt);
2549 return $this->
setData(self::WEIGHT, $weight);
2560 if ($typeId !== $this->
_getData(
'type_id')) {
2561 $this->_typeInstance =
null;
2563 return $this->
setData(self::TYPE_ID, $typeId);
2599 foreach ($mediaGallery as
$image) {
2601 ->mediaGalleryEntryConverterPool
2602 ->getConverterByMediaType(
$image[
'media_type'])
2603 ->convertTo($this,
$image);
2604 $entries[] = $entry;
2617 $mediaGallery = $this->getMediaGallery(
'images');
2618 if ($mediaGallery ===
null) {
2623 return $convertedEntries;
2635 if ($mediaGalleryEntries !==
null) {
2637 foreach ($mediaGalleryEntries as $entry) {
2639 ->mediaGalleryEntryConverterPool
2640 ->getConverterByMediaType($entry->getMediaType())
2641 ->convertFrom($entry);
2643 $this->
setData(
'media_gallery', [
'images' => $images]);
2656 return $this->
_getData(
'entity_id');
2676 private function getLinkRepository()
2678 if (
null === $this->linkRepository) {
2680 ->get(\
Magento\Catalog\Api\ProductLinkRepositoryInterface::class);
2690 private function getMediaGalleryProcessor()
2692 if (
null === $this->mediaGalleryProcessor) {
2694 ->get(\
Magento\Catalog\Model\Product\Gallery\Processor::class);
2725 return $this->
getData(
'quantity_and_stock_status');
2742 $this->
setData(
'quantity_and_stock_status', $quantityAndStockStatusData);
2759 return $this->
getData(
'stock_data');
getMediaAttributeValues()
$_productFlatIndexerProcessor
setMediaGalleryEntries(array $mediaGalleryEntries=null)
addAttributeUpdate($code, $value, $store)
toArray(array $arrAttributes=[])
setOptions(array $options=null)
setAttributeSetId($attributeSetId)
isVisibleInSiteVisibility()
getVisibleInCatalogStatuses()
getAvailableInCategories()
$_productEavIndexerProcessor
_getExtensionAttributes()
elseif(isset( $params[ 'redirect_parent']))
canBeShowInCategory($categoryId)
getCalculatedFinalPrice()
getAttributes($groupId=null, $skipSuper=false)
getAttributeText($attributeCode)
processBuyRequest(\Magento\Framework\DataObject $buyRequest)
$_catalogProductVisibility
getRelatedProductCollection()
_setExtensionAttributes(\Magento\Framework\Api\ExtensionAttributesInterface $extensionAttributes)
setQuantityAndStockStatus($quantityAndStockStatusData)
setData($key, $value=null)
$productLinkExtensionFactory
addCustomOption($code, $value, $product=null)
$entityCollectionProvider
isProductsHasSku(array $productIds)
getCrossSellProductCollection()
$mediaGalleryEntryConverterPool
setExtensionAttributes(\Magento\Catalog\Api\Data\ProductExtensionInterface $extensionAttributes)
canAffectOptions($value=null)
getRelatedLinkCollection()
addImageToMediaGallery($file, $mediaAttribute=null, $move=false, $exclude=true)
const CACHE_PRODUCT_CATEGORY_TAG
getUpSellLinkCollection()
addOption(Product\Option $option)
getGiftMessageAvailable()
setOrigData($key=null, $data=null)
lockAttribute($attributeCode)
getUpSellProductCollection()
convertToMediaGalleryInterface(array $mediaGallery)
getCrossSellLinkCollection()
__construct(\Magento\Framework\Model\Context $context, \Magento\Framework\Registry $registry, \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory, AttributeValueFactory $customAttributeFactory, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Catalog\Api\ProductAttributeRepositoryInterface $metadataService, Product\Url $url, Product\Link $productLink, \Magento\Catalog\Model\Product\Configuration\Item\OptionFactory $itemOptionFactory, \Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory $stockItemFactory, \Magento\Catalog\Model\Product\OptionFactory $catalogProductOptionFactory, \Magento\Catalog\Model\Product\Visibility $catalogProductVisibility, \Magento\Catalog\Model\Product\Attribute\Source\Status $catalogProductStatus, \Magento\Catalog\Model\Product\Media\Config $catalogProductMediaConfig, Product\Type $catalogProductType, \Magento\Framework\Module\Manager $moduleManager, \Magento\Catalog\Helper\Product $catalogProduct, \Magento\Catalog\Model\ResourceModel\Product $resource, \Magento\Catalog\Model\ResourceModel\Product\Collection $resourceCollection, \Magento\Framework\Data\CollectionFactory $collectionFactory, \Magento\Framework\Filesystem $filesystem, \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry, \Magento\Catalog\Model\Indexer\Product\Flat\Processor $productFlatIndexerProcessor, \Magento\Catalog\Model\Indexer\Product\Price\Processor $productPriceIndexerProcessor, \Magento\Catalog\Model\Indexer\Product\Eav\Processor $productEavIndexerProcessor, CategoryRepositoryInterface $categoryRepository, Product\Image\CacheFactory $imageCacheFactory, \Magento\Catalog\Model\ProductLink\CollectionProvider $entityCollectionProvider, \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider, \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory, \Magento\Catalog\Api\Data\ProductLinkExtensionFactory $productLinkExtensionFactory, EntryConverterPool $mediaGalleryEntryConverterPool, \Magento\Framework\Api\DataObjectHelper $dataObjectHelper, \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor, array $data=[], \Magento\Eav\Model\Config $config=null, FilterProductCustomAttribute $filterCustomAttribute=null)
getDefaultAttributeSetId()
getUrlInStore($params=[])
unlockAttribute($attributeCode)
getProductEntitiesInfo($columns=null)
getCustomAttributesCodes()
foreach($product->getExtensionAttributes() ->getBundleProductOptions() as $option) $buyRequest
setProductLinks(array $links=null)
getProductUrl($useSid=null)
isLockedAttribute($attributeCode)
setTypeInstance($instance)
$_catalogProductMediaConfig
getVisibleInSiteVisibilities()
getData($key='', $index=null)
dataHasChangedFor($field)
setAssociatedProductIds(array $productIds)
setPriceCalculation($calculate=true)
$_productPriceIndexerProcessor
$params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE]
setCustomOptions(array $options)
setCategoryCollection(\Magento\Framework\Data\Collection $categoryCollection)
setVisibility($visibility)
setTierPrices(array $tierPrices=null)
getProductOptionsCollection()
isDeleted($isDeleted=null)
getQuantityAndStockStatus()
if(!isset($_GET['name'])) $name