/**
  * {@inheritDoc}
  */
 public function getProduct()
 {
     if ($this->_productID && !parent::getProduct() && $this->_loaders->exists('product')) {
         $product = $this->_loaders->get('product')->getByID($this->_productID);
         $this->setProduct($product);
     }
     return parent::getProduct();
 }
 /**
  * {@inheritDoc}
  */
 public function getRewardOptions()
 {
     if (null === $this->_rewardOptions) {
         $rewardOptions = $this->_loaders->get('reward_option')->load($this);
         if (!$rewardOptions) {
             throw new \LogicException('Could not load reward options!');
         }
         foreach ($rewardOptions as $rewardOption) {
             $this->addRewardOption($rewardOption);
         }
     }
     return parent::getRewardOptions();
 }
 /**
  * Lazy load the prices for the bundle
  */
 private function _loadPrices()
 {
     $prices = $this->_loaders->get('price')->getPrices($this);
     foreach ($prices as $currencyID => $price) {
         $this->setPrice($price, $currencyID);
     }
 }
 /**
  * {@inheritDoc}
  */
 public function getRewardConfig()
 {
     if (null === $this->_rewardConfig) {
         if (null === $this->_rewardConfigID) {
             throw new \LogicException('No reward config ID set on ReferralProxy object!');
         }
         $rewardConfig = $this->_loaders->get('reward_config')->load($this);
         if (!$rewardConfig) {
             throw new \LogicException('Could not load reward config with ID `' . $this->_rewardConfigID . '`');
         }
         $this->setRewardConfig($rewardConfig);
     }
     return parent::getRewardConfig();
 }
    protected function _loadProduct($productIDs, $limit = null)
    {
        if (!is_array($productIDs)) {
            $productIDs = (array) $productIDs;
        }
        if (0 === $this->_entityLoaders->count()) {
            throw new \LogicException('Cannot load products when entity loaders are not set.');
        }
        $cachedProducts = [];
        // Load products from cache if limit is not set. If limit is set this complicates the following query so
        // this step is skipped.
        if (null === $limit) {
            foreach ($productIDs as $key => $id) {
                if ($this->_productCache->exists($id)) {
                    $cachedProduct = $this->_productCache->get($id);
                    // Only load deleted products from the cache if `_includeDeleted` is set to true
                    if ($this->_includeDeleted || !$cachedProduct->authorship->isDeleted()) {
                        $cachedProducts[] = $cachedProduct;
                        unset($productIDs[$key]);
                    }
                }
            }
        } else {
            $this->_checkLimit($limit);
        }
        // If there are no uncached products remaining, return the cached product/s
        if (count($productIDs) <= 0) {
            return $this->_returnArray ? $cachedProducts : array_shift($cachedProducts);
        }
        $result = $this->_query->run('SELECT
				product.product_id   AS id,
				product.product_id   AS catalogueID,
				product.created_at   AS createdAt,
				product.created_by   AS createdBy,
				product.updated_at   AS updatedAt,
				product.updated_by   AS updatedBy,
				product.deleted_at   AS deletedAt,
				product.deleted_by   AS deletedBy,
				product.brand        AS brand,
				product.type		 AS type,
				product.name         AS name,
				product.category     AS category,
				product.tax_strategy AS taxStrategy,
				product.tax_rate     AS taxRate,
				product.supplier_ref AS supplierRef,
				product.weight_grams AS weight,

				product_info.display_name      AS displayName,
				product_info.sort_name         AS sortName,
				product_info.description       AS description,
				product_info.short_description AS shortDescription,
				product_info.notes             AS notes,

				product_export.export_description            AS exportDescription,
				product_export.export_value                  AS exportValue,
				product_export.export_manufacture_country_id AS exportManufactureCountryID,
				product_export.export_code                   AS exportCode
			FROM
				product
			LEFT JOIN
				product_info ON (product.product_id = product_info.product_id)
			LEFT JOIN
				product_export ON (product.product_id = product_export.product_id)
			WHERE
				product.product_id 	 IN (?ij)
				' . (!$this->_includeDeleted ? 'AND product.deleted_at IS NULL' : '') . '
			' . ($limit ? 'LIMIT 0, ' . (int) $limit : '') . '
		', array((array) $productIDs));
        $tags = $this->_query->run('SELECT
				product_tag.product_id  AS id,
				product_tag.name        AS name
			FROM
				product_tag
			WHERE
				product_tag.product_id IN (?ij)
		', array((array) $productIDs));
        $products = $result->bindTo('Message\\Mothership\\Commerce\\Product\\ProductProxy', [$this->_locale, $this->_priceTypes, $this->_defaultCurrency, $this->_entityLoaders, clone $this->_taxStrategy]);
        foreach ($result as $key => $data) {
            // needs to set the product type if inclusive to get the base tax
            if ($products[$key]->getTaxStrategy()->getName() === 'inclusive') {
                $products[$key]->getTaxStrategy()->setProductType($data->type);
            }
            $data->taxRate = (double) $data->taxRate;
            $data->exportValue = (double) $data->exportValue;
            $products[$key]->authorship->create(new DateTimeImmutable(date('c', $data->createdAt)), $data->createdBy);
            if ($data->updatedAt) {
                $products[$key]->authorship->update(new DateTimeImmutable(date('c', $data->updatedAt)), $data->updatedBy);
            }
            if ($data->deletedAt) {
                $products[$key]->authorship->delete(new DateTimeImmutable(date('c', $data->deletedAt)), $data->deletedBy);
            }
            foreach ($tags as $k => $tag) {
                if ($tag->id == $data->id) {
                    $products[$key]->tags[$k] = $tag->name;
                }
            }
            $this->_loadType($products[$key], $data->type);
            // Add product to cache
            $this->_productCache->add($products[$key]);
        }
        // Merge cached products and main products array
        $products = array_merge($products, $cachedProducts);
        return count($products) == 1 && !$this->_returnArray ? array_shift($products) : $products;
    }