657 lines
20 KiB
PHP
657 lines
20 KiB
PHP
<?php
|
|
|
|
/**
|
|
* SOTESHOP/stProductOptionsPlugin
|
|
* Ten plik należy do aplikacji stProductOptionsPlugin opartej na licencji (Open License SOTE) Otwarta Licencja SOTE.
|
|
* Nie zmieniaj tego pliku, jeśli chcesz korzystać z automatycznych aktualizacji oprogramowania.
|
|
* Jeśli chcesz wprowadzać swoje modyfikacje do programu, zapoznaj się z dokumentacją, jak zmieniać
|
|
* oprogramowanie bez zmiany kodu bazowego http://www.sote.pl/modifications
|
|
*
|
|
* @author Daniel Mendalka <daniel.mendalka@sote.pl>
|
|
*
|
|
* @package stProductOptionsPlugin
|
|
* @subpackage libs
|
|
*/
|
|
class ProductOptionsValuePeer extends BaseProductOptionsValuePeer
|
|
{
|
|
protected static
|
|
$selectedItems = array(),
|
|
$doSelectByProduct = array(),
|
|
$getPriceType = array(),
|
|
$colorFilters = null;
|
|
|
|
const version = 1;
|
|
|
|
public static $hide_no_stock = false;
|
|
|
|
/**
|
|
* Zwraca listę opcji bez korzenia
|
|
*
|
|
* @param Criteria $c
|
|
* @param mixed $con
|
|
* @return array
|
|
* @throws PropelException
|
|
*/
|
|
public static function doSelectWithoutRoot(Criteria $c, $con = null)
|
|
{
|
|
$results = [];
|
|
$c = clone $c;
|
|
$c->add(self::PRODUCT_OPTIONS_VALUE_ID, null, Criteria::ISNOTNULL);
|
|
|
|
return self::doSelectJoinProductOptionsField($c, $con);
|
|
}
|
|
|
|
public static function doCountLeafsJoinProduct(Criteria $c = null, $con = null)
|
|
{
|
|
if($c == null)
|
|
{
|
|
$c = new Criteria();
|
|
}
|
|
|
|
$user = sfContext::getInstance()->getUser();
|
|
$filters = sfContext::getInstance()->getRequest()->getParameter('filters', array());
|
|
|
|
|
|
$c->add(self::LFT, self::RGT.'-'.self::LFT.'=1', Criteria::CUSTOM);
|
|
$c->addAscendingOrderByColumn(self::LFT);
|
|
$c->addJoin(self::PRODUCT_OPTIONS_FIELD_ID, BaseProductOptionsFieldPeer::ID);
|
|
$c->addJoin(self::ID, ProductOptionsValueI18nPeer::ID.' AND '.ProductOptionsValueI18nPeer::CULTURE.'=\''.$user->getCulture().'\'', Criteria::LEFT_JOIN);
|
|
$c->add(BaseProductOptionsFieldPeer::OPT_NAME, null, Criteria::ISNOTNULL);
|
|
|
|
return self::doCountJoinProduct($c, $con);
|
|
}
|
|
|
|
public static function doSelectLeafsJoinProduct(Criteria $c = null, $con = null)
|
|
{
|
|
if($c == null)
|
|
{
|
|
$c = new Criteria();
|
|
}
|
|
|
|
$user = sfContext::getInstance()->getUser();
|
|
$filters = sfContext::getInstance()->getRequest()->getParameter('filters', array());
|
|
|
|
$c->add(self::LFT, self::RGT.'-'.self::LFT.'=1', Criteria::CUSTOM);
|
|
$c->addAscendingOrderByColumn(self::LFT);
|
|
$c->addJoin(self::PRODUCT_OPTIONS_FIELD_ID, BaseProductOptionsFieldPeer::ID);
|
|
$c->addJoin(self::ID, ProductOptionsValueI18nPeer::ID.' AND '.ProductOptionsValueI18nPeer::CULTURE.'=\''.$user->getCulture().'\'', Criteria::LEFT_JOIN);
|
|
$c->add(BaseProductOptionsFieldPeer::OPT_NAME, null, Criteria::ISNOTNULL);
|
|
return self::doSelectJoinProduct($c, $con);
|
|
|
|
}
|
|
|
|
public static function updateIsActive(ProductOptionsValue $option)
|
|
{
|
|
$sql = sprintf('UPDATE %s SET %s = ? WHERE %s = ? AND %s BETWEEN ? AND ?', self::TABLE_NAME, self::IS_ACTIVE, self::PRODUCT_ID, self::LFT);
|
|
$ps = Propel::getConnection()->prepareStatement($sql);
|
|
$ps->setBoolean(1, $option->getIsActive());
|
|
$ps->setInt(2, $option->getProductId());
|
|
$ps->setInt(3, $option->getLft());
|
|
$ps->setInt(4, $option->getRgt());
|
|
|
|
return $ps->executeUpdate();
|
|
|
|
|
|
$s = new Criteria();
|
|
$s->add(self::LFT, sprintf('%s BETWEEN %d AND %d', self::LFT, $option->getLft(), $option->getRgt()));
|
|
$s->add(self::PRODUCT_ID, $option->getProductId());
|
|
|
|
$u = new Criteria();
|
|
$u->add(self::IS_ACTIVE, $option->getIsActive());
|
|
|
|
BasePeer::doUpdate($s, $u, Propel::getConnection());
|
|
}
|
|
|
|
public static function updateStock($product, $update_product = true, $return_stock = true)
|
|
{
|
|
if ($product)
|
|
{
|
|
$is_object = is_object($product);
|
|
|
|
if ($is_object && !$product->hasStockManagmentWithOptions())
|
|
{
|
|
return $product->getStock();
|
|
}
|
|
|
|
$id = $is_object ? $product->getId() : $product;
|
|
$con = Propel::getConnection();
|
|
|
|
$con->executeQuery(sprintf('UPDATE %1$s v LEFT JOIN %1$s c ON c.LFT BETWEEN v.LFT AND v.RGT AND c.PRODUCT_ID = %2$s AND c.RGT - c.LFT = 1 AND c.STOCK > 0 AND c.IS_ACTIVE = 1 SET v.STOCK = IFNULL(c.STOCK, 0) WHERE v.PRODUCT_ID = %2$s AND v.RGT - v.LFT > 1 AND v.IS_ACTIVE = 1',
|
|
self::TABLE_NAME,
|
|
$id
|
|
));
|
|
|
|
if ($update_product || $return_stock)
|
|
{
|
|
$stock = self::getStock($product);
|
|
|
|
if ($update_product)
|
|
{
|
|
stDepository::set($product, $stock);
|
|
}
|
|
|
|
return $stock;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static function getStock($product)
|
|
{
|
|
$config = stConfig::getInstance('stProduct');
|
|
|
|
if ('max' == $config->get('product_options_stock_computation', 'max'))
|
|
{
|
|
return self::getMaxStock($product);
|
|
}
|
|
|
|
return self::getSumStock($product);
|
|
}
|
|
|
|
public static function getSumStock($product)
|
|
{
|
|
if (is_object($product) && !$product instanceof Product)
|
|
{
|
|
throw new InvalidArgumentException(sprintf('Przekazany obiekt musi być instancją Product (przekazany: %s)', get_class($product)));
|
|
}
|
|
|
|
$id = is_object($product) ? $product->getId() : $product;
|
|
$c = new Criteria();
|
|
$c->addSelectColumn('SUM('.self::STOCK.')');
|
|
$c->add(self::PRODUCT_ID, $id);
|
|
$c->add(self::IS_ACTIVE, true);
|
|
$c->add(self::LFT, sprintf('%s - %s = 1', self::RGT, self::LFT), Criteria::CUSTOM);
|
|
$rs = self::doSelectRs($c);
|
|
|
|
if ($rs && $rs->next())
|
|
{
|
|
$row = $rs->getRow();
|
|
return !empty($row[0]) ? $row[0] : 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static function getMaxStock($product)
|
|
{
|
|
if ($product)
|
|
{
|
|
if (is_object($product) && !$product instanceof Product)
|
|
{
|
|
throw new InvalidArgumentException(sprintf('Przekazany obiekt musi być instancją Product (przekazany: %s)', get_class($product)));
|
|
}
|
|
|
|
$id = is_object($product) ? $product->getId() : $product;
|
|
$c = new Criteria();
|
|
$c->addSelectColumn('MAX('.self::STOCK.')');
|
|
$c->add(self::IS_ACTIVE, true);
|
|
$c->add(self::PRODUCT_ID, $id);
|
|
$rs = self::doSelectRs($c);
|
|
|
|
if ($rs && $rs->next())
|
|
{
|
|
$row = $rs->getRow();
|
|
return !empty($row[0]) ? $row[0] : 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static function updateTotalStock($product_id)
|
|
{
|
|
self::updateStock($product_id);
|
|
}
|
|
|
|
public static function unsetTemplate($product)
|
|
{
|
|
$c = new Criteria();
|
|
$c->add(self::DEPTH, 0);
|
|
$c->add(self::PRODUCT_ID, $product->getId());
|
|
|
|
$root = self::doSelectOne($c);
|
|
if(is_object($root))
|
|
{
|
|
$root->setProductOptionsTemplateId(null);
|
|
$root->save();
|
|
}
|
|
}
|
|
|
|
public static function doSelectByIds($ids)
|
|
{
|
|
$options = array();
|
|
|
|
foreach ($ids as $id)
|
|
{
|
|
$option = self::retrieveByPk($id);
|
|
if (null === $option)
|
|
{
|
|
return array();
|
|
}
|
|
|
|
$options[] = $option;
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
public static function getProductOptionsStock($product)
|
|
{
|
|
$c = new Criteria();
|
|
$c->add(self::PRODUCT_ID,$product->getId());
|
|
$c->add(self::LFT, self::RGT.'-'.self::LFT.'=1', Criteria::CUSTOM);
|
|
|
|
$stock = 0;
|
|
foreach (self::doSelect($c) as $option)
|
|
{
|
|
$stock+= $option->getStock();
|
|
}
|
|
return $stock;
|
|
}
|
|
|
|
public static function retrieveByPkWithProduct($pk)
|
|
{
|
|
$c = new Criteria();
|
|
|
|
$c->add(self::ID, $pk);
|
|
|
|
$options = self::doSelectJoinProduct($c);
|
|
|
|
return isset($options[0]) ? $options[0] : null;
|
|
}
|
|
|
|
public static function retrieveByPksWithProduct($pks)
|
|
{
|
|
$c = new Criteria();
|
|
|
|
$c->add(self::ID, $pks, Criteria::IN);
|
|
|
|
return self::doSelectJoinProduct($c);
|
|
}
|
|
|
|
public static function setSelectedItems($id, $items = array())
|
|
{
|
|
self::$selectedItems[$id] = $items;
|
|
}
|
|
|
|
public static function getSelectedItems($id)
|
|
{
|
|
if (isset(self::$selectedItems[$id])) return self::$selectedItems[$id];
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Zwraca opcje root produktu
|
|
*
|
|
* @param Product|int $product Id lub instancja modelu produktu
|
|
* @return ProductOptionsValue|null
|
|
*/
|
|
public static function getRoot($product)
|
|
{
|
|
$c = new Criteria();
|
|
$c->add(self::PRODUCT_ID, is_object($product) ? $product->getId() : $product);
|
|
$c->add(self::PRODUCT_OPTIONS_VALUE_ID, null, Criteria::ISNULL);
|
|
|
|
return self::doSelectOne($c);
|
|
}
|
|
|
|
/**
|
|
* Zwraca lub tworzy opcje root produktu
|
|
*
|
|
* @param Product|int $product Id lub instancja modelu produktu
|
|
* @return ProductOptionsValue
|
|
*/
|
|
public static function getOrCreateRoot($product, string $priceType = null)
|
|
{
|
|
$root = self::getRoot($product);
|
|
|
|
if (null === $root)
|
|
{
|
|
$root = new ProductOptionsValue();
|
|
$root->setPriceType($priceType);
|
|
$root->setProductId($product->getId());
|
|
$root->makeRoot();
|
|
$root->save();
|
|
}
|
|
|
|
return $root;
|
|
}
|
|
|
|
public static function getPriceType($product)
|
|
{
|
|
$id = is_object($product) ? $product->getId() : $product;
|
|
|
|
if (!isset(self::$getPriceType[$id]))
|
|
{
|
|
$c = new Criteria();
|
|
|
|
$c->add(self::PRODUCT_OPTIONS_VALUE_ID, null, Criteria::ISNULL);
|
|
|
|
$c->add(self::PRICE_TYPE, null, Criteria::ISNOTNULL);
|
|
|
|
$c->addSelectColumn(self::PRICE_TYPE);
|
|
|
|
$c->add(self::PRODUCT_ID, $id);
|
|
|
|
$c->setLimit(1);
|
|
|
|
$rs = self::doSelectRS($c);
|
|
|
|
$config = stConfig::getInstance(null, 'stProduct');
|
|
|
|
self::$getPriceType[$id] = $rs->next() ? $rs->getString(1) : $config->get('price_type');
|
|
}
|
|
|
|
return self::$getPriceType[$id];
|
|
}
|
|
|
|
public static function doSelectByProduct($product, $hide_no_stock = true)
|
|
{
|
|
$id = $product->getId();
|
|
|
|
if (!isset(self::$doSelectByProduct[$id]))
|
|
{
|
|
$c = new Criteria();
|
|
|
|
$c->add(self::PRODUCT_ID, $id);
|
|
|
|
self::addOrderCriteria($c);
|
|
|
|
$c->add(self::DEPTH, 1);
|
|
$c->add(self::IS_ACTIVE, true);
|
|
|
|
if ($hide_no_stock)
|
|
{
|
|
self::addHideWithEmptyStockCriteria($product, $c);
|
|
}
|
|
|
|
self::$doSelectByProduct[$id] = self::doSelectJoinProductOptionsField($c);
|
|
}
|
|
|
|
return self::$doSelectByProduct[$id];
|
|
}
|
|
|
|
/**
|
|
* Dodaje kryteria ukrywania opcji z 0 stanem magazynowym
|
|
*
|
|
* @param Product $product
|
|
* @param Criteria|Criterion $c
|
|
* @param bool $addOr
|
|
* @return void
|
|
*/
|
|
public static function addHideWithEmptyStockCriteria(Product $product, $c, $addOr = false)
|
|
{
|
|
if ($product->getStockManagment() == ProductPeer::STOCK_PRODUCT_OPTIONS && $product->getConfiguration()->get('hide_options_with_empty_stock'))
|
|
{
|
|
$value = sprintf('(%1$s IS NULL OR %1$s > 0)', self::STOCK);
|
|
|
|
if ($c instanceof Criterion)
|
|
{
|
|
$criteria = new Criteria();
|
|
$criterion = $criteria->getNewCriterion(self::STOCK, $value, Criteria::CUSTOM);
|
|
|
|
if ($addOr)
|
|
{
|
|
$c->addOr($criterion);
|
|
}
|
|
else
|
|
{
|
|
$c->addAnd($criterion);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ($addOr)
|
|
{
|
|
$c->addOr(self::STOCK, $value, Criteria::CUSTOM);
|
|
}
|
|
else
|
|
{
|
|
$c->addAnd(self::STOCK, $value, Criteria::CUSTOM);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static function getColorImageDir($product_id, $system = false, $root_path = null)
|
|
{
|
|
if (null === $root_path)
|
|
{
|
|
$root_path = '/uploads/options';
|
|
}
|
|
|
|
$path = $root_path.'/'.$product_id;
|
|
|
|
if ($system)
|
|
{
|
|
return sfConfig::get('sf_web_dir').$path;
|
|
}
|
|
|
|
return $path;
|
|
}
|
|
|
|
public static function getColorImagePath($product_id, $option_id, $color_image_name, $system = false, $root_path = null)
|
|
{
|
|
return self::getColorImageDir($product_id, $system, $root_path).'/'.$option_id.'-'.$color_image_name;
|
|
}
|
|
|
|
public static function addOrderCriteria(Criteria $c)
|
|
{
|
|
$c->addAscendingOrderByColumn(ProductOptionsFieldPeer::FIELD_ORDER);
|
|
|
|
$c->addAscendingOrderByColumn(self::PRODUCT_OPTIONS_FIELD_ID);
|
|
|
|
$c->addAscendingOrderByColumn(self::LFT);
|
|
}
|
|
|
|
public static function clearImportHash($id)
|
|
{
|
|
ExportMd5HashPeer::clearHash($id, 'Product', 'product_options');
|
|
}
|
|
|
|
public static function clearStatic()
|
|
{
|
|
self::$selectedItems = array();
|
|
self::$doSelectByProduct = array();
|
|
self::$getPriceType = array();
|
|
self::$colorFilters = null;
|
|
}
|
|
|
|
public static function updateProductColor($product)
|
|
{
|
|
$object = is_object($product);
|
|
|
|
$product_id = $object ? $product->getId() : $product;
|
|
|
|
if (null === self::$colorFilters)
|
|
{
|
|
$c = new Criteria();
|
|
$c->addSelectColumn(ProductOptionsFilterPeer::ID);
|
|
$c->add(ProductOptionsFilterPeer::FILTER_TYPE, 2);
|
|
$rs = ProductOptionsFilterPeer::doSelectRs($c);
|
|
self::$colorFilters = array();
|
|
|
|
while($rs->next())
|
|
{
|
|
self::$colorFilters[] = $rs->getInt(1);
|
|
}
|
|
}
|
|
|
|
$colors = array();
|
|
|
|
if (self::$colorFilters)
|
|
{
|
|
$c = new Criteria();
|
|
$c->addSelectColumn(self::ID);
|
|
$c->addSelectColumn(self::COLOR);
|
|
$c->addSelectColumn(self::STOCK);
|
|
$c->addSelectColumn(self::USE_IMAGE_AS_COLOR);
|
|
$c->addSelectColumn(self::SF_ASSET_ID);
|
|
$c->add(self::IS_ACTIVE, true);
|
|
$c->add(self::PRODUCT_ID, $product_id);
|
|
$c->add(self::OPT_FILTER_ID, self::$colorFilters, Criteria::IN);
|
|
$c->addAscendingOrderByColumn(self::LFT);
|
|
$c->addGroupByColumn(self::COLOR);
|
|
$rs = self::doSelectRs($c);
|
|
|
|
while($rs->next())
|
|
{
|
|
$row = $rs->getRow();
|
|
$colors[] = array(
|
|
'color' => $row[3] ? self::getColorImagePath($product_id, $row[0], $row[1]) : $row[1],
|
|
'stock' => $row[2],
|
|
'image_as_color' => $row[3],
|
|
'image_id' => $row[4],
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!$object)
|
|
{
|
|
$sel = new Criteria();
|
|
$sel->add(ProductPeer::ID, $product_id);
|
|
|
|
$up = new Criteria();
|
|
$up->add(ProductPeer::OPTIONS_COLOR, serialize($colors));
|
|
|
|
BasePeer::doUpdate($sel, $up, Propel::getConnection());
|
|
}
|
|
else
|
|
{
|
|
$product->setOptionsColor($colors);
|
|
}
|
|
}
|
|
|
|
public static function doUpdatePriceType(ProductOptionsValue $value)
|
|
{
|
|
$sel = new Criteria();
|
|
$sel->add(self::PRODUCT_ID, $value->getProductId());
|
|
|
|
$up = new Criteria();
|
|
$up->add(self::PRICE_TYPE, $value->getPriceType());
|
|
|
|
return BasePeer::doUpdate($sel, $up, Propel::getConnection());
|
|
}
|
|
|
|
public static function doInsert($values, $con = null)
|
|
{
|
|
|
|
foreach (sfMixer::getCallables('BaseProductOptionsValuePeer:doInsert:pre') as $callable)
|
|
{
|
|
$ret = call_user_func($callable, 'BaseProductOptionsValuePeer', $values, $con);
|
|
if (false !== $ret)
|
|
{
|
|
return $ret;
|
|
}
|
|
}
|
|
|
|
|
|
if ($con === null) {
|
|
$con = Propel::getConnection(self::DATABASE_NAME);
|
|
}
|
|
|
|
if ($values instanceof Criteria) {
|
|
$criteria = clone $values; // rename for clarity
|
|
$criteria->remove(self::ID);
|
|
} else {
|
|
$criteria = $values->buildCriteria(); // build Criteria from ProductOptionsValue object
|
|
if (!$values->isColumnModified(self::ID)) {
|
|
$criteria->remove(self::ID); // remove pkey col since this table uses auto-increment
|
|
}
|
|
}
|
|
|
|
// Set the correct dbName
|
|
$criteria->setDbName(self::DATABASE_NAME);
|
|
|
|
try {
|
|
// use transaction because $criteria could contain info
|
|
// for more than one table (I guess, conceivably)
|
|
$con->begin();
|
|
$pk = BasePeer::doInsert($criteria, $con);
|
|
$con->commit();
|
|
} catch(PropelException $e) {
|
|
$con->rollback();
|
|
throw $e;
|
|
}
|
|
|
|
|
|
foreach (sfMixer::getCallables('BaseProductOptionsValuePeer:doInsert:post') as $callable)
|
|
{
|
|
call_user_func($callable, 'BaseProductOptionsValuePeer', $values, $con, $pk);
|
|
}
|
|
|
|
return $pk;
|
|
}
|
|
|
|
public static function doSelectRoot(Product $product)
|
|
{
|
|
$c = new Criteria();
|
|
$c->add(self::PRODUCT_ID, $product->getId());
|
|
$c->add(self::PRODUCT_OPTIONS_FIELD_ID, null, Criteria::ISNULL);
|
|
$c->setLimit(1);
|
|
|
|
$results = self::doSelectWithI18n($c, $product->getCulture());
|
|
|
|
return $results ? $results[0] : null;
|
|
}
|
|
|
|
public static function doSelectRootAsJsTreeFormat(Product $product)
|
|
{
|
|
self::setPostHydrateMethod(array('ProductOptionsValuePeer', 'jsTreeFormatHydrate'));
|
|
|
|
$result = self::doSelectRoot($product);
|
|
|
|
self::setPostHydrateMethod(null);
|
|
|
|
return $result;
|
|
}
|
|
|
|
public static function doSelectByFieldId($fieldId, $culture)
|
|
{
|
|
$c = new Criteria();
|
|
|
|
if ($fieldId)
|
|
{
|
|
$c->add(self::PRODUCT_OPTIONS_FIELD_ID, $fieldId);
|
|
}
|
|
|
|
$c->addJoin(self::PRODUCT_OPTIONS_FIELD_ID, ProductOptionsFieldPeer::ID);
|
|
|
|
self::addOrderCriteria($c);
|
|
|
|
return self::doSelectWithI18n($c, $culture);
|
|
}
|
|
|
|
public static function doSelectByFieldIdAsJsTreeFormat($fieldId, $culture)
|
|
{
|
|
self::setPostHydrateMethod(array('ProductOptionsValuePeer', 'jsTreeFormatHydrate'));
|
|
|
|
$results = self::doSelectByFieldId($fieldId, $culture);
|
|
|
|
self::setPostHydrateMethod(null);
|
|
|
|
return $results;
|
|
}
|
|
|
|
public static function jsTreeFormatHydrate(ProductOptionsValue $value)
|
|
{
|
|
if ($value->isRoot() && $value->hasChildren())
|
|
{
|
|
$state = "open";
|
|
}
|
|
else
|
|
{
|
|
$state = $value->hasChildren() ? "closed" : "item_leaf";
|
|
}
|
|
|
|
return array(
|
|
"data" => $value->isRoot() ? $value->getProduct()->getName() : $value->getValue(),
|
|
"attr" => array("id" => "value-".$value->getId(), "rel" => $value->isRoot() ? "root" : "value"),
|
|
"metadata" => array("id" => $value->getId()),
|
|
"state" => $state,
|
|
"children" => $value->isRoot() && $value->hasChildren() ? ProductOptionsFieldPeer::doSelectByValueIdAsJsTreeFormat($value->getId(), $value->getCulture()) : null,
|
|
);
|
|
}
|
|
}
|