123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Wishlist\Model;
- use Magento\Catalog\Api\ProductRepositoryInterface;
- use Magento\Catalog\Model\Product\Configuration\Item\ItemInterface;
- use Magento\Framework\Exception\NoSuchEntityException;
- use Magento\Framework\Model\AbstractModel;
- use Magento\Wishlist\Model\Item\Option;
- use Magento\Wishlist\Model\Item\OptionFactory;
- use Magento\Wishlist\Model\ResourceModel\Item\Option\CollectionFactory;
- use Magento\Catalog\Model\Product\Exception as ProductException;
- /**
- * Wishlist item model
- *
- * @method int getWishlistId()
- * @method \Magento\Wishlist\Model\Item setWishlistId(int $value)
- * @method int getProductId()
- * @method \Magento\Wishlist\Model\Item setProductId(int $value)
- * @method int getStoreId()
- * @method \Magento\Wishlist\Model\Item setStoreId(int $value)
- * @method string getAddedAt()
- * @method \Magento\Wishlist\Model\Item setAddedAt(string $value)
- * @method string getDescription()
- * @method \Magento\Wishlist\Model\Item setDescription(string $value)
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- *
- * @api
- * @since 100.0.2
- */
- class Item extends AbstractModel implements ItemInterface
- {
- /**
- * Custom path to download attached file
- * @var string
- */
- protected $_customOptionDownloadUrl = 'wishlist/index/downloadCustomOption';
- /**
- * Prefix of model events names
- *
- * @var string
- */
- protected $_eventPrefix = 'wishlist_item';
- /**
- * Parameter name in event
- *
- * In observe method you can use $observer->getEvent()->getItem() in this case
- *
- * @var string
- */
- protected $_eventObject = 'item';
- /**
- * Item options array
- *
- * @var Option[]
- */
- protected $_options = [];
- /**
- * Item options by code cache
- *
- * @var array
- */
- protected $_optionsByCode = [];
- /**
- * Not Represent options
- *
- * @var string[]
- */
- protected $_notRepresentOptions = ['info_buyRequest'];
- /**
- * Flag stating that options were successfully saved
- *
- * @var bool|null
- */
- protected $_flagOptionsSaved = null;
- /**
- * @var \Magento\Store\Model\StoreManagerInterface
- */
- protected $_storeManager;
- /**
- * @var \Magento\Framework\Stdlib\DateTime\DateTime
- */
- protected $_date;
- /**
- * @var \Magento\Catalog\Model\ResourceModel\Url
- */
- protected $_catalogUrl;
- /**
- * @var OptionFactory
- */
- protected $_wishlistOptFactory;
- /**
- * @var CollectionFactory
- */
- protected $_wishlOptionCollectionFactory;
- /**
- * @var \Magento\Catalog\Model\ProductTypes\ConfigInterface
- */
- protected $productTypeConfig;
- /**
- * @var ProductRepositoryInterface
- */
- protected $productRepository;
- /**
- * Serializer interface instance.
- *
- * @var \Magento\Framework\Serialize\Serializer\Json
- */
- private $serializer;
- /**
- * @param \Magento\Framework\Model\Context $context
- * @param \Magento\Framework\Registry $registry
- * @param \Magento\Store\Model\StoreManagerInterface $storeManager
- * @param \Magento\Framework\Stdlib\DateTime\DateTime $date
- * @param \Magento\Catalog\Model\ResourceModel\Url $catalogUrl
- * @param OptionFactory $wishlistOptFactory
- * @param CollectionFactory $wishlOptionCollectionFactory
- * @param \Magento\Catalog\Model\ProductTypes\ConfigInterface $productTypeConfig
- * @param ProductRepositoryInterface $productRepository
- * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
- * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
- * @param array $data
- * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
- * @SuppressWarnings(PHPMD.ExcessiveParameterList)
- */
- public function __construct(
- \Magento\Framework\Model\Context $context,
- \Magento\Framework\Registry $registry,
- \Magento\Store\Model\StoreManagerInterface $storeManager,
- \Magento\Framework\Stdlib\DateTime\DateTime $date,
- \Magento\Catalog\Model\ResourceModel\Url $catalogUrl,
- OptionFactory $wishlistOptFactory,
- CollectionFactory $wishlOptionCollectionFactory,
- \Magento\Catalog\Model\ProductTypes\ConfigInterface $productTypeConfig,
- ProductRepositoryInterface $productRepository,
- \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
- \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
- array $data = [],
- \Magento\Framework\Serialize\Serializer\Json $serializer = null
- ) {
- $this->productTypeConfig = $productTypeConfig;
- $this->_storeManager = $storeManager;
- $this->_date = $date;
- $this->_catalogUrl = $catalogUrl;
- $this->_wishlistOptFactory = $wishlistOptFactory;
- $this->_wishlOptionCollectionFactory = $wishlOptionCollectionFactory;
- $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
- ->get(\Magento\Framework\Serialize\Serializer\Json::class);
- parent::__construct($context, $registry, $resource, $resourceCollection, $data);
- $this->productRepository = $productRepository;
- }
- /**
- * Initialize resource model
- *
- * @return void
- */
- protected function _construct()
- {
- $this->_init(\Magento\Wishlist\Model\ResourceModel\Item::class);
- }
- /**
- * Set quantity. If quantity is less than 0 - set it to 1
- *
- * @param int $qty
- * @return $this
- */
- public function setQty($qty)
- {
- $this->setData('qty', $qty >= 0 ? $qty : 1);
- return $this;
- }
- /**
- * Check if two options array are identical
- *
- * @param array $options1
- * @param array $options2
- * @return bool
- */
- protected function _compareOptions($options1, $options2)
- {
- $skipOptions = ['id', 'qty', 'return_url'];
- foreach ($options1 as $code => $value) {
- if (in_array($code, $skipOptions)) {
- continue;
- }
- if (!isset($options2[$code]) || $options2[$code] != $value) {
- return false;
- }
- }
- return true;
- }
- /**
- * Register option code
- *
- * @param Option $option
- * @return $this
- * @throws \Magento\Framework\Exception\LocalizedException
- */
- protected function _addOptionCode($option)
- {
- if (!isset($this->_optionsByCode[$option->getCode()])) {
- $this->_optionsByCode[$option->getCode()] = $option;
- } else {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('An item option with code %1 already exists.', $option->getCode())
- );
- }
- return $this;
- }
- /**
- * Checks that item model has data changes.
- * Call save item options if model isn't need to save in DB
- *
- * @return boolean
- */
- protected function _hasModelChanged()
- {
- if (!$this->hasDataChanges()) {
- return false;
- }
- return $this->_getResource()->hasDataChanged($this);
- }
- /**
- * Save item options
- *
- * @return $this
- */
- public function saveItemOptions()
- {
- foreach ($this->_options as $index => $option) {
- if ($option->isDeleted()) {
- $option->delete();
- unset($this->_options[$index]);
- unset($this->_optionsByCode[$option->getCode()]);
- } else {
- $option->save();
- }
- }
- $this->_flagOptionsSaved = true;
- // Report to watchers that options were saved
- return $this;
- }
- /**
- * Mark option save requirement
- *
- * @param bool $flag
- * @return void
- */
- public function setIsOptionsSaved($flag)
- {
- $this->_flagOptionsSaved = $flag;
- }
- /**
- * Were options saved?
- *
- * @return bool
- */
- public function isOptionsSaved()
- {
- return $this->_flagOptionsSaved;
- }
- /**
- * Save item options after item saved
- *
- * @return $this
- */
- public function afterSave()
- {
- $this->saveItemOptions();
- return parent::afterSave();
- }
- /**
- * Validate wish list item data
- *
- * @return bool
- * @throws \Magento\Framework\Exception\LocalizedException
- */
- public function validate()
- {
- if (!$this->getWishlistId()) {
- throw new \Magento\Framework\Exception\LocalizedException(__('We can\'t specify a wish list.'));
- }
- if (!$this->getProductId()) {
- throw new \Magento\Framework\Exception\LocalizedException(__('Cannot specify product.'));
- }
- return true;
- }
- /**
- * Check required data
- *
- * @return $this
- */
- public function beforeSave()
- {
- parent::beforeSave();
- // validate required item data
- $this->validate();
- // set current store id if it is not defined
- if ($this->getStoreId() === null) {
- $this->setStoreId($this->_storeManager->getStore()->getId());
- }
- // set current date if added at data is not defined
- if ($this->getAddedAt() === null) {
- $this->setAddedAt($this->_date->gmtDate());
- }
- return $this;
- }
- /**
- * Load item by product, wishlist and shared stores
- *
- * @param int $wishlistId
- * @param int $productId
- * @param array $sharedStores
- * @return $this
- */
- public function loadByProductWishlist($wishlistId, $productId, $sharedStores)
- {
- $this->_getResource()->loadByProductWishlist($this, $wishlistId, $productId, $sharedStores);
- $this->_afterLoad();
- $this->setOrigData();
- return $this;
- }
- /**
- * Retrieve item product instance
- *
- * @throws \Magento\Framework\Exception\LocalizedException
- * @return \Magento\Catalog\Model\Product
- */
- public function getProduct()
- {
- $product = $this->_getData('product');
- if ($product === null) {
- if (!$this->getProductId()) {
- throw new \Magento\Framework\Exception\LocalizedException(__('Cannot specify product.'));
- }
- try {
- $product = $this->productRepository->getById($this->getProductId(), false, $this->getStoreId(), true);
- } catch (NoSuchEntityException $e) {
- throw new \Magento\Framework\Exception\LocalizedException(__('Cannot specify product.'), $e);
- }
- $this->setData('product', $product);
- }
- /**
- * Reset product final price because it related to custom options
- */
- $product->setFinalPrice(null);
- $product->setCustomOptions($this->_optionsByCode);
- return $product;
- }
- /**
- * Add or Move item product to shopping cart
- *
- * Return true if product was successful added or exception with code
- * Return false for disabled or unvisible products
- *
- * @param \Magento\Checkout\Model\Cart $cart
- * @param bool $delete delete the item after successful add to cart
- * @return bool
- * @throws \Magento\Catalog\Model\Product\Exception
- */
- public function addToCart(\Magento\Checkout\Model\Cart $cart, $delete = false)
- {
- $product = $this->getProduct();
- $storeId = $this->getStoreId();
- if ($product->getStatus() != \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) {
- return false;
- }
- if (!$product->isVisibleInSiteVisibility()) {
- if ($product->getStoreId() == $storeId) {
- return false;
- }
- $urlData = $this->_catalogUrl->getRewriteByProductStore([$product->getId() => $storeId]);
- if (!isset($urlData[$product->getId()])) {
- return false;
- }
- $product->setUrlDataObject(new \Magento\Framework\DataObject($urlData));
- $visibility = $product->getUrlDataObject()->getVisibility();
- if (!in_array($visibility, $product->getVisibleInSiteVisibilities())) {
- return false;
- }
- }
- if (!$product->isSalable()) {
- throw new ProductException(__('Product is not salable.'));
- }
- $buyRequest = $this->getBuyRequest();
- $cart->addProduct($product, $buyRequest);
- if (!$product->isVisibleInSiteVisibility()) {
- $cart->getQuote()->getItemByProduct($product)->setStoreId($storeId);
- }
- if ($delete) {
- $this->delete();
- }
- return true;
- }
- /**
- * Retrieve Product View Page URL
- *
- * If product has required options add special key to URL
- *
- * @return string
- */
- public function getProductUrl()
- {
- $product = $this->getProduct();
- $query = [];
- if ($product->getTypeInstance()->hasRequiredOptions($product)) {
- $query['options'] = 'cart';
- }
- return $product->getUrlModel()->getUrl($product, ['_query' => $query]);
- }
- /**
- * Returns formatted buy request - object, holding request received from
- * product view page with keys and options for configured product
- *
- * @return \Magento\Framework\DataObject
- */
- public function getBuyRequest()
- {
- $option = $this->getOptionByCode('info_buyRequest');
- $initialData = $option ? $this->serializer->unserialize($option->getValue()) : [];
- if ($initialData instanceof \Magento\Framework\DataObject) {
- $initialData = $initialData->getData();
- }
- $buyRequest = new \Magento\Framework\DataObject($initialData);
- $buyRequest->setOriginalQty($buyRequest->getQty())->setQty($this->getQty() * 1);
- return $buyRequest;
- }
- /**
- * Merge data to item info_buyRequest option
- *
- * @param array|\Magento\Framework\DataObject $buyRequest
- * @return $this
- */
- public function mergeBuyRequest($buyRequest)
- {
- if ($buyRequest instanceof \Magento\Framework\DataObject) {
- $buyRequest = $buyRequest->getData();
- }
- if (empty($buyRequest) || !is_array($buyRequest)) {
- return $this;
- }
- $oldBuyRequest = $this->getBuyRequest()->getData();
- $sBuyRequest = $this->serializer->serialize($buyRequest + $oldBuyRequest);
- $option = $this->getOptionByCode('info_buyRequest');
- if ($option) {
- $option->setValue($sBuyRequest);
- } else {
- $this->addOption(['code' => 'info_buyRequest', 'value' => $sBuyRequest]);
- }
- return $this;
- }
- /**
- * Set buy request - object, holding request received from
- * product view page with keys and options for configured product
- *
- * @param \Magento\Framework\DataObject $buyRequest
- * @return $this
- */
- public function setBuyRequest($buyRequest)
- {
- $buyRequest->setId($this->getId());
- $_buyRequest = $this->serializer->serialize($buyRequest->getData());
- $this->setData('buy_request', $_buyRequest);
- return $this;
- }
- /**
- * Check product representation in item
- *
- * @param \Magento\Catalog\Model\Product $product
- * @param \Magento\Framework\DataObject $buyRequest
- * @return bool
- */
- public function isRepresent($product, $buyRequest)
- {
- if ($this->getProductId() != $product->getId()) {
- return false;
- }
- $selfOptions = $this->getBuyRequest()->getData();
- if (empty($buyRequest) && !empty($selfOptions)) {
- return false;
- }
- if (empty($selfOptions) && !empty($buyRequest)) {
- if (!$product->isComposite()) {
- return true;
- } else {
- return false;
- }
- }
- $requestArray = $buyRequest->getData();
- if (!$this->_compareOptions($requestArray, $selfOptions)) {
- return false;
- }
- if (!$this->_compareOptions($selfOptions, $requestArray)) {
- return false;
- }
- return true;
- }
- /**
- * Check product representation in item
- *
- * @param \Magento\Catalog\Model\Product $product
- * @return bool
- */
- public function representProduct($product)
- {
- $itemProduct = $this->getProduct();
- if ($itemProduct->getId() != $product->getId()) {
- return false;
- }
- $itemOptions = $this->getOptionsByCode();
- $productOptions = $product->getCustomOptions();
- if (!$this->compareOptions($itemOptions, $productOptions)) {
- return false;
- }
- if (!$this->compareOptions($productOptions, $itemOptions)) {
- return false;
- }
- return true;
- }
- /**
- * Check if two options array are identical
- * First options array is prerogative
- * Second options array checked against first one
- *
- * @param array $options1
- * @param array $options2
- * @return bool
- */
- public function compareOptions($options1, $options2)
- {
- foreach ($options1 as $option) {
- $code = $option->getCode();
- if (in_array($code, $this->_notRepresentOptions)) {
- continue;
- }
- if (!isset($options2[$code]) || $options2[$code]->getValue() != $option->getValue()) {
- return false;
- }
- }
- return true;
- }
- /**
- * Initialize item options
- *
- * @param array $options
- * @return $this
- */
- public function setOptions($options)
- {
- foreach ($options as $option) {
- $this->addOption($option);
- }
- return $this;
- }
- /**
- * Get all item options
- *
- * @return Option[]
- */
- public function getOptions()
- {
- return $this->_options;
- }
- /**
- * Get all item options as array with codes in array key
- *
- * @return array
- */
- public function getOptionsByCode()
- {
- return $this->_optionsByCode;
- }
- /**
- * Add option to item
- *
- * @param Option|\Magento\Framework\DataObject|array $option
- * @return $this
- * @throws \Magento\Framework\Exception\LocalizedException
- */
- public function addOption($option)
- {
- if (is_array($option)) {
- $option = $this->_wishlistOptFactory->create()->setData($option)->setItem($this);
- } elseif ($option instanceof Option) {
- $option->setItem($this);
- } elseif ($option instanceof \Magento\Framework\DataObject) {
- $option = $this->_wishlistOptFactory->create()->setData($option->getData())
- ->setProduct($option->getProduct())
- ->setItem($this);
- } else {
- throw new \Magento\Framework\Exception\LocalizedException(__('Invalid item option format.'));
- }
- $exOption = $this->getOptionByCode($option->getCode());
- if ($exOption) {
- $exOption->addData($option->getData());
- } else {
- $this->_addOptionCode($option);
- $this->_options[] = $option;
- }
- return $this;
- }
- /**
- * Remove option from item options
- *
- * @param string $code
- * @return $this
- */
- public function removeOption($code)
- {
- $option = $this->getOptionByCode($code);
- if ($option) {
- $option->isDeleted(true);
- }
- return $this;
- }
- /**
- * Get item option by code
- *
- * @param string $code
- * @return Option|null
- */
- public function getOptionByCode($code)
- {
- if (isset($this->_optionsByCode[$code]) && !$this->_optionsByCode[$code]->isDeleted()) {
- return $this->_optionsByCode[$code];
- }
- return null;
- }
- /**
- * Returns whether Qty field is valid for this item
- *
- * @return bool
- */
- public function canHaveQty()
- {
- $product = $this->getProduct();
- return !$this->productTypeConfig->isProductSet($product->getTypeId());
- }
- /**
- * Get current custom option download url
- *
- * @return string
- */
- public function getCustomDownloadUrl()
- {
- return $this->_customOptionDownloadUrl;
- }
- /**
- * Sets custom option download url
- *
- * @param string $url
- * @return void
- */
- public function setCustomDownloadUrl($url)
- {
- $this->_customOptionDownloadUrl = $url;
- }
- /**
- * Returns special download params (if needed) for custom option with type = 'file'.
- * Needed to implement \Magento\Catalog\Model\Product\Configuration\Item\Interface.
- *
- * We have to customize only controller url, so return it.
- *
- * @return null|\Magento\Framework\DataObject
- */
- public function getFileDownloadParams()
- {
- $params = new \Magento\Framework\DataObject();
- $params->setUrl($this->_customOptionDownloadUrl);
- return $params;
- }
- /**
- * Loads item together with its options (default load() method doesn't load options).
- * If we need to load only some of options, then option code or array of option codes
- * can be provided in $optionsFilter.
- *
- * @param int $id
- * @param null|string|array $optionsFilter
- *
- * @return $this
- */
- public function loadWithOptions($id, $optionsFilter = null)
- {
- $this->load($id);
- if (!$this->getId()) {
- return $this;
- }
- $options = $this->_wishlOptionCollectionFactory->create()->addItemFilter($this);
- if ($optionsFilter) {
- $options->addFieldToFilter('code', $optionsFilter);
- }
- $this->setOptions($options->getOptionsByItem($this));
- return $this;
- }
- }
|