Version: current

      1 <?php
      2
      3 /**
      4  * Реализация корзины
      5  *
      6  * @package cart
      7  * @author inxo
      8  */
      9 class Cart extends Object {
     10
     11     static $cache = false;
     12
     13     // новый
     14     static function add_new_item(OrderItem $item) {
     15         $currentItems = self::get_items();
     16         foreach($currentItems as $currentItem) {
     17             if ($currentItem->hasSameContent($item)) // !!! TODO Проверить, нужно ли canAddQuantityValue тут !!!
     18                 return self::add_item($currentItem->ItemIndex);
     19         }
     20         if ($item->canAddQuantityValue($item->Quantity)) {
     21             self::set_item($item->getProductID(), $item);
     22         }
     23     }
     24
     25     // +1
     26     static function add_item($itemIndex, $quantity = 1) {
     27         $unserializedItem = self::get_item($itemIndex);
     28         $unserializedItem->addQuantityValue($quantity);
     29         self::set_item($itemIndex, $unserializedItem);
     30     }
     31
     32     // -1
     33     static function remove_item($itemIndex, $count = 1) {
     34         $unserializedItem = self::get_item($itemIndex);
     35         $newQuantity = $unserializedItem->getQuantity() - $count;
     36         if ($newQuantity > 0) {
     37             $unserializedItem->setQuantityValue($newQuantity);
     38             self::set_item($itemIndex, $unserializedItem);
     39         } else {
     40             self::set_item($itemIndex, false);
     41         }
     42     }
     43
     44     // имя корзины
     45     private static function item_list() {
     46         return 'cart_items';
     47     }
     48
     49     // индексация корзины
     50     private static function cart_index() {
     51         //$hash = (Member::currentUserID() ? Member::currentUserID() : self::cart_hash());
     52         $hash = self::cart_hash();
     53         return self::item_list() . '_' . $hash;
     54     }
     55
     56     // индексация корзины
     57     private static function cart_hash() {
     58         return (Cookie::get('cart_hash') ? Cookie::get('cart_hash') : self::generate_cart_hash());
     59     }
     60
     61     // индексация корзины
     62     private static function generate_cart_hash() {
     63         $sc = SiteConfig::current_site_config();
     64         $hash = md5(time() . rand());
     65         Cookie::set('cart_hash', $hash, ($sc->CachedCartLifeTime ? $sc->CachedCartLifeTime : 30)); //
     66         return $hash;
     67     }
     68
     69     // отчистка корзины
     70     static function clear() {
     71         self::clean_cache(self::cart_index());
     72         if ($member = Member::currentUser()) {
     73             $member->CartData = serialize(array());
     74             $member->write();
     75         }
     76     }
     77
     78     // удалить
     79     static function remove_all_item($itemIndex) {
     80         self::set_item($itemIndex, false);
     81     }
     82
     83     // установить количество
     84     static function set_quantity_item($itemIndex, $quantity) {
     85         $unserializedItem = self::get_item($itemIndex);
     86         $unserializedItem->setQuantityValue($quantity);
     87         self::set_item($itemIndex, $unserializedItem);
     88     }
     89
     90     // получить количество
     91     static function get_quantity_item($itemIndex) {
     92         $unserializedItem = self::get_item($itemIndex);
     93         return $unserializedItem->Quantity;
     94     }
     95
     96     // получаем список того, что в корзине
     97     static function get_items() {
     98         $items = array();
     99         $currentItems = unserialize(self::get_cached_data(self::cart_index()));
    100         if ($currentItems) {
    101             foreach ($currentItems as $currentItem) {
    102                 if ($currentItem != null) {
    103                     array_push($items, $currentItem);
    104                 }
    105             }
    106         }
    107         return $items;
    108     }
    109
    110     // получить элемент корзины
    111     private static function get_item($itemIndex) {
    112         $items = self::get_items();
    113         if ($items && count($items)) {
    114             foreach($items as $item) {
    115                 if ($item->ItemIndex == $itemIndex) {
    116                     return $item;
    117                 }
    118             }
    119         }
    120         return false;
    121     }
    122
    123     // установить новый элемент
    124     private static function set_item($index, OrderItem $item) {
    125         $allItems = self::get_items();
    126         $find = false;
    127         if ($allItems) {
    128             foreach($allItems as $key=>$oneItem) {
    129                 if ($oneItem->ItemIndex == $index) {
    130                     $find = true;
    131                     if ($item) {
    132                         $item->ItemIndex = $index;
    133                         $allItems[$key] = $item;
    134                     } else {
    135                         unset($allItems[$key]);
    136                     }
    137                     break;
    138                 }
    139             }
    140         }
    141         if (!$find) {
    142             if ($item) {
    143                 $item->ItemIndex = $index;
    144                 array_push($allItems, $item);
    145             }
    146         }
    147
    148         self::set_cached_data(self::cart_index(), serialize($allItems));
    149
    150         $order = self::current_order();
    151         $order->extend('onAfterSetCart', $allItems);
    152
    153         if ($member = Member::currentUser()) {
    154             $member->CartData = serialize($allItems);
    155             $member->write();
    156         }
    157         return;
    158     }
    159
    160     // проверка на пустоту
    161     static function has_items() {
    162         return self::get_items();
    163     }
    164
    165     // проверим есть ли такой товар в корзине
    166     static function in_cart($itemIndex) {
    167         return self::get_item($itemIndex);
    168     }
    169
    170     // текущий заказ
    171     static function current_order() {
    172         $order = new Order();
    173         $order->IsCart = true;
    174         $order->ClearCartLink = Cart_Controller::clear_link();
    175         $order->update(self::get_info());
    176         return $order;
    177     }
    178
    179     static function get_info($name = null) {
    180         $info = Session::get('cart.info');
    181         if (!$info) $info = array();
    182         if ($name) {
    183             return isset($info[$name]) ? $info[$name] : null;
    184         }
    185         return $info;
    186     }
    187
    188     static function set_info($name, $value) {
    189         $info = self::get_info();
    190         $info[$name] = $value;
    191         Session::set('cart.info', $info);
    192     }
    193
    194     static function get_cached_cart() {
    195         if (($member = Member::currentUser()) && ($cartData = unserialize($member->CartData))) {
    196             return $cartData;
    197         }
    198         return false;
    199     }
    200
    201     static function update_cart_from_cache() {
    202         if ($cachedCart = self::get_cached_cart()) {
    203             foreach($cachedCart as $item) {
    204                 if ($item->getProduct() && $item->getProduct()->ExistsOnLive) {
    205                     if ($currentItems = self::get_items()) {
    206                         $has = false;
    207                         foreach($currentItems as $currentItem) {
    208                             if ($currentItem->hasSameContent($item)) {
    209                                 $has = true;
    210                             }
    211                         }
    212                         if (!$has) {
    213                             self::add_new_item($item);
    214                         }
    215                     } else {
    216                         self::add_new_item($item);
    217                     }
    218                 }
    219             }
    220         }
    221         if ($member = Member::currentUser()) {
    222             $member->CartData = serialize(self::get_items());
    223             $member->write();
    224         }
    225         return false;
    226     }
    227
    228     // функции кеша
    229     static function get_cache() {
    230         if (!self::$cache) {
    231             $sc = SiteConfig::current_site_config();
    232             self::$cache = SS_Cache::set_cache_lifetime('cart', ($sc->CachedCartLifeTime ? $sc->CachedCartLifeTime : 30)*24*60*60); // в секундах
    233             self::$cache = SS_Cache::factory('cart');
    234         }
    235         return self::$cache;
    236     }
    237
    238     static function get_cached_data($key) {
    239         if (!$key) return false;
    240         return unserialize(self::get_cache()->load($key));
    241     }
    242
    243     static function set_cached_data($key, $data) {
    244         if (!$key) return false;
    245         return self::get_cache()->save(serialize($data), $key);
    246     }
    247
    248     static function clean_cache($key) {
    249         self::get_cache()->remove($key);
    250     }
    251 }
    252
    253 class Cart_Controller extends Controller {
    254
    255     static $allowed_actions = array('add', 'clear', 'additem', 'removeitem', 'removeallitem', 'setquantityitem', 'jsoncart', 'in_cart');
    256     static $URLSegment = 'cartaction';
    257
    258     static $cart_template = 'Cart';
    259     static function set_cart_template($v) { self::$cart_template = $v; }
    260
    261
    262     function Link($action = null) {
    263         return Controller::join_links(Director::baseURL(), self::$URLSegment, $action);
    264     }
    265
    266     static function clear_link() {
    267         return Controller::join_links(Director::baseURL(), self::$URLSegment, 'clear');
    268     }
    269
    270     static function add_item_link($id) {
    271         return Controller::join_links(Director::baseURL(), self::$URLSegment, 'additem', $id);
    272     }
    273
    274     static function remove_item_link($id) {
    275         return Controller::join_links(Director::baseURL(), self::$URLSegment, 'removeitem', $id);
    276     }
    277
    278     static function remove_all_item_link($id) {
    279         return Controller::join_links(Director::baseURL(), self::$URLSegment, 'removeallitem', $id);
    280     }
    281
    282     static function set_quantity_item_link($id) {
    283         return Controller::join_links(Director::baseURL(), self::$URLSegment, 'setquantityitem', $id);
    284     }
    285
    286     function init() {
    287         parent::init();
    288         HTTP::set_cache_age(0);
    289     }
    290
    291     /**
    292      * Добавление в корзину по кнопке
    293      * /cartaction/add?itemId=<ID>&Num=<Num>
    294      *
    295      * @param array $data - данные POST или GET запроса
    296      * @return mixed - редирект или данные для ajax
    297      */
    298     function add($data) {
    299         if (isset($data['itemId']) && is_numeric($data['itemId'])) {
    300             $id = $data['itemId'];
    301             $Num = 1;
    302             if (isset($data['Num']) && is_numeric($data['Num'])) {
    303                 $Num = $data['Num'];
    304             }
    305             $variationId = false;
    306             if (isset($data['variationId']) && is_numeric($data['variationId'])) {
    307                 $variationId = (int)$data['variationId'];
    308                 $id .= "_{$variationId}";
    309             }
    310             if (Cart::in_cart($id)) {
    311                 Cart::add_item($id, $Num);
    312             } else {
    313                 $product = DataObject::get_by_id(singleton('Product')->ClassName, (int)$id);
    314                 if ($product->hasMethod('Variations') && $product->Variations()->exists()) {
    315                     if ($variationId) {
    316                         $product->VariationID = $variationId;
    317                     } else {
    318                         // Если у товара есть вариации, то его нельзя сложить в корзину без указания нужной вариации
    319                         // !! TODO сделать как-то более культурно !!
    320                         // !!! ТОЧНО СДЕЛАТЬ !!!
    321                         return false;
    322                     }
    323                 }
    324 //              $item = new OrderItem($product, $Num);
    325                 $item = Object::create('OrderItem', $product, $Num);
    326                 Cart::add_new_item($item);
    327             }
    328
    329             Session::clear('Cart.Process');
    330             if (!$this->isAjax())
    331                 Director::redirectBack();
    332             return $this->CartBlock();
    333         }
    334     }
    335
    336     /**
    337      * Удалить все из корзины
    338      * /cartaction/clear
    339      */
    340     function clear() {
    341         Cart::clear();
    342         return ($this->isAjax()) ? $this->renderCart() : Director::redirectBack();
    343     }
    344
    345     /**
    346      * +1 товар
    347      * /cartaction/additem/<ID>
    348      *
    349      * @return <type>
    350      */
    351     function additem() {
    352         $itemId = $this->urlParams['ID'];
    353         if ($itemId) {
    354             Cart::add_item($itemId);
    355             return ($this->isAjax()) ? $this->renderCart() : Director::redirectBack();
    356         }
    357         return false;
    358     }
    359
    360     /**
    361      * -1 товар
    362      * /cartaction/removeitem/<ID>
    363      *
    364      * @return <type>
    365      */
    366     function removeitem() {
    367         $itemId = $this->urlParams['ID'];
    368         if ($itemId) {
    369             Cart::remove_item($itemId);
    370             return ($this->isAjax()) ? $this->renderCart() : Director::redirectBack();
    371         }
    372         return false;
    373     }
    374
    375     /**
    376      * Удаляет товар из корзины
    377      * /cartaction/removeallitem/<ID>
    378      *
    379      * @return <type>
    380      */
    381     function removeallitem() {
    382         $itemId = $this->urlParams['ID'];
    383         if ($itemId) {
    384             Cart::remove_all_item($itemId);
    385             return ($this->isAjax()) ? $this->renderCart() : Director::redirectBack();
    386         }
    387         return false;
    388     }
    389
    390     /**
    391      * Устанавливает ко-во товара в корзине
    392      * /cartaction/setquantityitem/<ID>?quantity=<Num>
    393      *
    394      * @return <type>
    395      */
    396     function setquantityitem() {
    397         $itemId = $this->urlParams['ID'];
    398         $quantity = $_REQUEST['quantity'];
    399         if ($itemId && is_numeric($quantity) && is_int($quantity + 0) && $quantity > 0) {
    400             Cart::set_quantity_item($itemId, $quantity);
    401             return ($this->isAjax()) ? $this->renderCart() : Director::redirectBack();
    402         }
    403         return false;
    404     }
    405
    406     /**
    407      * JSON представление корзины
    408      * /cartaction/jsoncart
    409      *
    410      * @return <type>
    411      */
    412     public function jsoncart() {
    413         return self::json_code();
    414     }
    415
    416     /**
    417      * JSON представление товара в корзине
    418      * /cartaction/in_cart/<ID>
    419      *
    420      * @return <type>
    421      */
    422     public function in_cart() {
    423         $itemId = $this->urlParams['ID'];
    424         if ($itemId && is_numeric($itemId)) {
    425             if (Cart::in_cart($itemId)) {
    426                 $currentOrder = Cart::current_order();
    427                 $js = array();
    428                 if ($items = $currentOrder->Items()) {
    429                     foreach ($items as $item) {
    430                         if ($item->getProductID() == $itemId) {
    431                             $item->updateForAjax($js);
    432                         }
    433                     }
    434                     return Convert::array2json($js);
    435                 }
    436             }
    437             return false;
    438         }
    439         return false;
    440     }
    441
    442     /**
    443      * Генерирует html код корзины для ajax запросов ее модификации
    444      *
    445      * @return string
    446      */
    447     protected function renderCart() {
    448         return $this->renderWith(self::$cart_template, Cart::current_order());
    449     }
    450
    451     /**
    452      * Информация о корзине в формате json
    453      * @return String
    454      */
    455     protected static function json_code() {
    456         $currentOrder = Cart::current_order();
    457         $js = array();
    458
    459         $items = $currentOrder->Items();
    460
    461         // Получаем информацию по каждой позиции
    462         if ($items) {
    463             foreach ($items as $item)
    464                 $item->updateForAjax($js);
    465         }
    466
    467         // Получаем информацию об общем кол-ве
    468         $currentOrder->updateForAjax($js);
    469         return Convert::array2json($js);
    470     }
    471
    472     // Запрет прямого доступа к корзине
    473     function index() {
    474         Director::redirect('');
    475     }
    476
    477 }
    478

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -