/** * Fill the object's arrProducts array * @param array|null * @return array */ protected function findProducts($arrCacheIds = null) { $time = time(); $arrCategories = $this->findCategories($this->iso_category_scope); list($arrFilters, $arrSorting, $strWhere, $arrValues) = $this->getFiltersAndSorting(); $objProductData = $this->Database->prepare(IsotopeProduct::getSelectStatement() . "\n\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE p1.language=''" . (BE_USER_LOGGED_IN === true ? '' : " AND p1.published='1' AND (p1.start='' OR p1.start<{$time}) AND (p1.stop='' OR p1.stop>{$time})") . "AND (p1.id IN (SELECT pid FROM tl_iso_product_categories WHERE page_id IN (" . implode(',', $arrCategories) . "))\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tOR p1.pid IN (SELECT pid FROM tl_iso_product_categories WHERE page_id IN (" . implode(',', $arrCategories) . ")))" . (is_array($arrCacheIds) ? "AND (p1.id IN (" . implode(',', $arrCacheIds) . ") OR p1.pid IN (" . implode(',', $arrCacheIds) . "))" : '') . ($this->iso_list_where == '' ? '' : " AND {$this->iso_list_where}") . "{$strWhere} GROUP BY p1.id ORDER BY c.sorting")->execute($arrValues); return IsotopeFrontend::getProducts($objProductData, IsotopeFrontend::getReaderPageId(null, $this->iso_reader_jumpTo), true, $arrFilters, $arrSorting); }
/** * Adds the product urls to the array so they get indexed when the search index is being rebuilt in the maintenance module * @param array absolute page urls * @param int root page id * @return array extended array of absolute page urls */ public function addProductsToSearchIndex($arrPages, $intRootPageId = 0) { $time = time(); $arrIsotopeProductPages = array(); // get all products available $objProducts = $this->Database->execute(IsotopeProduct::getSelectStatement() . " WHERE p1.language='' AND p1.pid=0 AND p1.published=1 AND (p1.start='' OR p1.start<{$time}) AND (p1.stop='' OR p1.stop>{$time})"); $arrProducts = self::getProducts($objProducts); if (!count($arrProducts)) { return; } // if we have a root page id (sitemap.xml e.g.) we have to make sure we only consider categories in this tree $arrAllowedPageIds = array(); if ($intRootPageId > 0) { $arrAllowedPageIds = $this->getChildRecords($intRootPageId, 'tl_page'); } // get all the categories for every product foreach ($arrProducts as $objProduct) { $arrCategories = $objProduct->categories; // filter those that are allowed if (count($arrAllowedPageIds)) { $arrCategories = array_intersect($arrCategories, $arrAllowedPageIds); } if (!is_array($arrCategories) || !count($arrCategories)) { continue; } if (!is_array($arrCategories) || !count($arrCategories)) { continue; } $objCategoryPages = $this->Database->execute('SELECT * FROM tl_page WHERE id IN(' . implode(',', $arrCategories) . ')'); if (!$objCategoryPages->numRows) { continue; } while ($objCategoryPages->next()) { // set the reader jump to page $objProduct->reader_jumpTo = self::getReaderPageId($objCategoryPages); // generate the front end url $arrIsotopeProductPages[] = $this->Environment->base . ltrim($objProduct->href_reader, '/'); } } // the reader page id can be the same for several categories so we have to make sure we only index the product once $arrIsotopeProductPages = array_unique($arrIsotopeProductPages); return array_merge($arrPages, $arrIsotopeProductPages); }
/** * Construct the object * @param array * @param array * @param boolean */ public function __construct($arrData, $arrOptions = null, $blnLocked = false) { parent::__construct(); $this->import('Database'); $this->import('Isotope'); if (FE_USER_LOGGED_IN === true) { $this->import('FrontendUser', 'User'); } $this->blnLocked = $blnLocked; if ($arrData['pid'] > 0) { $this->arrData = $this->Database->execute("SELECT * FROM tl_iso_products WHERE id={$arrData['pid']}")->fetchAssoc(); } else { $this->arrData = $arrData; } if (!$this->arrData['type']) { return; } $this->formSubmit = 'iso_product_' . $this->arrData['id']; $this->arrType = $this->Database->execute("SELECT * FROM tl_iso_producttypes WHERE id=" . (int) $this->arrData['type'])->fetchAssoc(); $this->arrAttributes = $this->getSortedAttributes($this->arrType['attributes']); $this->arrVariantAttributes = $this->arrType['variants'] ? $this->getSortedAttributes($this->arrType['variant_attributes']) : array(); $this->arrCache['list_template'] = $this->arrType['list_template']; $this->arrCache['reader_template'] = $this->arrType['reader_template']; $this->arrOptions = is_array($arrOptions) ? $arrOptions : array(); // Allow to customize attributes if (isset($GLOBALS['ISO_HOOKS']['productAttributes']) && is_array($GLOBALS['ISO_HOOKS']['productAttributes'])) { foreach ($GLOBALS['ISO_HOOKS']['productAttributes'] as $callback) { $this->import($callback[0]); $this->{$callback}[0]->{$callback}[1]($this->arrAttributes, $this->arrVariantAttributes, $this); } } // Remove attributes not in this product type foreach ($this->arrData as $attribute => $value) { if (!in_array($attribute, $this->arrAttributes) && !in_array($attribute, $this->arrVariantAttributes) && $GLOBALS['TL_DCA']['tl_iso_products']['fields'][$attribute]['attributes']['legend'] != '') { unset($this->arrData[$attribute]); } } if (!$this->blnLocked) { if ($this->arrType['variants']) { $time = time(); // Find all possible variant options $objVariant = clone $this; $objVariants = $this->Database->execute(IsotopeProduct::getSelectStatement() . " WHERE p1.pid={$this->arrData['id']} AND p1.language=''" . (BE_USER_LOGGED_IN === true ? '' : " AND p1.published='1' AND (p1.start='' OR p1.start<{$time}) AND (p1.stop='' OR p1.stop>{$time})")); while ($objVariants->next()) { $objVariant->loadVariantData($objVariants->row(), false); if ($objVariant->available) { $arrVariantOptions = $objVariant->getOptions(true); $this->arrVariantOptions['ids'][] = $objVariant->id; $this->arrVariantOptions['options'][$objVariant->id] = $arrVariantOptions; $this->arrVariantOptions['variants'][$objVariant->id] = $objVariants->row(); foreach ($arrVariantOptions as $attribute => $value) { if (!in_array((string) $value, (array) $this->arrVariantOptions['attributes'][$attribute], true)) { $this->arrVariantOptions['attributes'][$attribute][] = (string) $value; } } } } // Find lowest price if (in_array('price', $this->arrVariantAttributes)) { if ($this->arrType['prices'] && count($this->arrVariantOptions['ids'])) { // Add "price_tiers" to variant attributes, so the field is updated through ajax $this->arrVariantAttributes[] = 'price_tiers'; $objProduct = $this->Database->execute("SELECT MIN(price) AS low_price, MAX(price) AS high_price\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM tl_iso_price_tiers\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE pid IN\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT p1.id, p1.pid FROM tl_iso_prices p1 LEFT JOIN tl_iso_products p2 ON p1.pid=p2.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tp1.pid IN (" . implode(',', $this->arrVariantOptions['ids']) . ")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAND p1.config_id IN (" . (int) $this->Isotope->Config->id . ",0)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAND p1.member_group IN(" . (FE_USER_LOGGED_IN === true && count($this->User->groups) ? implode(',', $this->User->groups) . ',' : '') . "0)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAND (p1.start='' OR p1.start<{$time})\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAND (p1.stop='' OR p1.stop>{$time})\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tORDER BY p1.config_id DESC, " . (FE_USER_LOGGED_IN === true && count($this->User->groups) ? 'p1.member_group=' . implode(' DESC, p1.member_group=', $this->User->groups) . ' DESC' : 'p1.member_group DESC') . ", p1.start DESC, p1.stop DESC\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) AS p\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tGROUP BY pid\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tGROUP BY min ORDER BY min ASC LIMIT 1"); } else { $objProduct = $this->Database->execute("SELECT MIN(price) AS low_price, MAX(price) AS high_price FROM tl_iso_products\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE pid=" . ($this->arrData['pid'] ? $this->arrData['pid'] : $this->arrData['id']) . " AND language=''" . (BE_USER_LOGGED_IN === true ? '' : " AND published='1' AND (start='' OR start<{$time}) AND (stop='' OR stop>{$time})") . " GROUP BY pid"); } if ($objProduct->low_price < $objProduct->high_price) { $this->arrCache['low_price'] = $objProduct->low_price; } else { $this->arrData['price'] = $objProduct->low_price; } } } if (in_array('price', $this->arrAttributes)) { // Add "price_tiers" to attributes, so the field is available in the template $this->arrAttributes[] = 'price_tiers'; $this->findPrice(); $this->arrData['original_price'] = $this->arrData['price']; } } if ($arrData['pid'] > 0) { $this->loadVariantData($arrData); } if ($this->blnLocked) { $this->arrData['sku'] = $arrData['sku']; $this->arrData['name'] = $arrData['name']; $this->arrData['price'] = $arrData['price']; } }
/** * Fetch products from database * @param string * @param boolean * @return array */ public function getProducts($strTemplate = '', $blnNoCache = false) { if (!is_array($this->arrProducts) || $blnNoCache) { $this->arrProducts = array(); $this->arrCache['lastAdded'] = 0; $lastAdded = 0; $objItems = $this->Database->prepare("SELECT * FROM " . $this->ctable . " WHERE pid=?")->executeUncached($this->id); while ($objItems->next()) { $objProductData = $this->Database->prepare(IsotopeProduct::getSelectStatement() . "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE p1.language='' AND p1.id=?")->limit(1)->execute($objItems->product_id); $strClass = $GLOBALS['ISO_PRODUCT'][$objProductData->product_class]['class']; if ($objProductData->numRows && $strClass != '') { try { $arrData = $this->blnLocked ? array_merge($objProductData->row(), array('sku' => $objItems->product_sku, 'name' => $objItems->product_name, 'price' => $objItems->price)) : $objProductData->row(); $objProduct = new $strClass($arrData, deserialize($objItems->product_options), $this->blnLocked); } catch (Exception $e) { $objProduct = new IsotopeProduct(array('id' => $objItems->product_id, 'sku' => $objItems->product_sku, 'name' => $objItems->product_name, 'price' => $objItems->price), deserialize($objItems->product_options), $this->blnLocked); } } else { $objProduct = new IsotopeProduct(array('id' => $objItems->product_id, 'sku' => $objItems->product_sku, 'name' => $objItems->product_name, 'price' => $objItems->price), deserialize($objItems->product_options), $this->blnLocked); } // Remove product from collection if it is no longer available if (!$objProduct->available) { $objProduct->cart_id = $objItems->id; $this->deleteProduct($objProduct); continue; } $objProduct->quantity_requested = $objItems->product_quantity; $objProduct->cart_id = $objItems->id; $objProduct->tax_id = $objItems->tax_id; $objProduct->reader_jumpTo_Override = $objItems->href_reader; if ($objItems->tstamp > $lastAdded) { $this->arrCache['lastAdded'] = $objItems->id; $lastAdded = $objItems->tstamp; } $this->arrProducts[] = $objProduct; } } if (strlen($strTemplate)) { $this->import('Isotope'); $objTemplate = new IsotopeTemplate($strTemplate); $objTemplate->products = $this->arrProducts; $objTemplate->surcharges = IsotopeFrontend::formatSurcharges($this->getSurcharges()); $objTemplate->subTotalLabel = $GLOBALS['TL_LANG']['MSC']['subTotalLabel']; $objTemplate->subTotalPrice = $this->Isotope->formatPriceWithCurrency($this->subTotal, false); $objTemplate->grandTotalLabel = $GLOBALS['TL_LANG']['MSC']['grandTotalLabel']; $objTemplate->grandTotalPrice = $this->Isotope->formatPriceWithCurrency($this->grandTotal, false); return $objTemplate->parse(); } return $this->arrProducts; }