public function swapItem($from_serial, $to_item_id, $user_id = NULL) { // default the user_id to the current logged in user if nothing was passed in $user_id = empty($user_id) ? SC::get('userdata.user_id') : intval($user_id); // validate that the serial we want to delete belongs to the user $ir = new InventoryReader($user_id); $ir->bySerial($from_serial); $rs = $ir->execute(); if (!$rs->isSuccess()) { return $this->throwError('Unable to load your inventory at this time. Please try again later. Error: ' . $rs->getError(), $rs); } $data = $rs->getItems(); // data is empty so that means the user doesn't own this serial if (empty($data)) { return $this->throwError('The item was not found in your inventory.'); } // validate that the item we want to swap to exists // to_item_id can be either an INT (item_id that we want to grant) or // an array of item_ids that we want to grant and how many of each we want to grant // get the ids of the items we want to grant $item_ids = array(); if (is_array($to_item_id)) { foreach ($to_item_id as $item) { $item_ids[] = $item['item_id']; } } else { $item_ids[] = $to_item_id; } // check to see if the items we want to grant exist $idr = new ItemDefinitionReader(); $idr->addIds($item_ids); if (!$idr->execute('__meta__')) { return $this->throwError('Unable to load item detail, please try again. ' . $idr->getError(), $idr); } $found_ids = $idr->getItemIds(); // if item_ids contains ids that arent in $found_ids then an item doesn't exist $difference = array_diff($item_ids, $found_ids); if (!empty($difference)) { return $this->throwError('Item(s) not found', $difference); } // at this point we have a valid serial that belongs to the user_id and valid items that we want to grant $txn = DaoFactory::create('transactionmanager'); // clear frozen status (if any) as we should allow users to open frozen letters $prop = PropertyReader::instance()->getProperties($from_serial, $user_id); $from_item_frozen_property = NULL; if (isset($prop['frozen']) && FrozenChecker::isFrozenByProperty($prop)) { $from_item_frozen_property = $prop['frozen']; // would be nice if we can attach $txn to $iw here, but it would create a dirty read // problem. we could potentially fail later after clearing the frozen status. we will live // with the unlikely case for now. $iw = new InventoryWriter(IW_APPCODE_FUNC_SWAP_ITEM); $iw->deleteProperty($from_serial, $user_id, INVENTORY_LOCATION_MAIN, 'frozen'); $iwr = $iw->execute(); if (!$iwr->isSuccess()) { $txn->rollback(); return $this->throwError($iwr->getError()); } } //delete item we are swapping out $iw = new InventoryWriter(IW_APPCODE_FUNC_SWAP_ITEM, $txn); $iw->deleteSerializedItem($user_id, $from_serial); //grant item(s) we are swapping in if (is_array($to_item_id)) { foreach ($to_item_id as $item) { $quantity = isset($item['quantity']) ? $item['quantity'] : 1; $iw->grantNewItems($user_id, $item['item_id'], $quantity); } } else { $iw->grantNewItems($user_id, $to_item_id, 1); } $iwr = $iw->execute(FALSE); if (!$iwr->isSuccess()) { $txn->rollback(); return $this->throwError($iwr->getError()); } // get the serials of the granted items $this->granted_items = $iwr->getGeneratedSerials(); if ($from_item_frozen_property) { // transfer the frozen property value to the swapped item // with packages it's not possible that a frozen item will grant multiple items. // all these items should be frozen $iw = new InventoryWriter(IW_APPCODE_FUNC_SWAP_ITEM, $txn); foreach ($this->granted_items as $new_serial) { $iw->setProperty($new_serial, $user_id, INVENTORY_LOCATION_MAIN, 'frozen', $from_item_frozen_property); } $iw->execute(FALSE); if (!$iwr->isSuccess()) { $txn->rollback(); return $this->throwError($iwr->getError()); } } $txn->commit(); // set the new serials associated with the item_ids return TRUE; }