1. Клиентская реализация через JavaScript
Принцип работы: Итеративное срабатывание события удаления для всех товаров.
<div class="clean-basket-wr">
<button type="button" class="btn-clean-basket" onclick="cleanBasket()">
Очистить корзину
</button>
</div> function cleanBasket() {
// Проверка подтверждения действия
if (!confirm('Вы уверены, что хотите очистить корзину?')) return;
const deleteButtons = document.querySelectorAll(
'[data-entity="basket-item-delete"]'
);
if (deleteButtons.length === 0) {
alert('Корзина уже пуста');
return;
}
// Асинхронное последовательное удаление
let index = 0;
const deleteNext = () => {
if (index < deleteButtons.length) {
deleteButtons[index].click();
index++;
setTimeout(deleteNext, 300); // Интервал для избежания блокировки
}
};
deleteNext();
}
Ограничения метода:
- Зависит от структуры DOM
- Не обрабатывает асинхронные операции
- Нет обработки ошибок
- Не удаляет отложенные товары
2. Серверная реализация через Legacy API
Безопасное удаление только активных товаров:
/**
* Очищает текущую активную корзину пользователя
*
* @return array Результат операции
*/
function cleanActiveBasket(): array
{
if (!CModule::IncludeModule('sale')) {
return ['success' => false, 'error' => 'Module "sale" not installed'];
}
$fuserId = CSaleBasket::GetBasketUserID();
$siteId = SITE_ID;
$errors = [];
$filter = [
'FUSER_ID' => $fuserId,
'LID' => $siteId,
'ORDER_ID' => 'null', // Только неоформленные товары
'DELAY' => 'N', // Исключить отложенные
'CAN_BUY' => 'Y', // Только доступные к покупке
'SUBSCRIBE' => 'N' // Исключить товары по подписке
];
$res = CSaleBasket::GetList(['ID' => 'ASC'], $filter);
while ($item = $res->Fetch()) {
if (!CSaleBasket::Delete($item['ID'])) {
$errors[] = "Ошибка удаления позиции ID: {$item['ID']}";
}
}
return [
'success' => empty($errors),
'count_deleted' => $res->SelectedRowsCount(),
'errors' => $errors
];
}
Ключевые параметры фильтра:
ORDER_ID => 'null': Только товары не в оформленных заказахDELAY => 'N': Исключает отложенные товарыCAN_BUY => 'Y': Только доступные для покупки товарыSUBSCRIBE => 'N': Исключает товары по подписке
3. Современная реализация через D7 API
Оптимальный подход для новых проектов:
use Bitrix\Main\Loader;
use Bitrix\Sale\Basket;
use Bitrix\Sale\Fuser;
class BasketService
{
public static function getUserBasket():object
{
return Sale\Basket::loadItemsForFUser(
\Bitrix\Sale\Fuser::getId(),
\Bitrix\Main\Context::getCurrent()->getSite()
);
}
/**
* Очищает активную корзину пользователя
*
* @return array
* @throws \Bitrix\Main\ArgumentException
* @throws \Bitrix\Main\ObjectPropertyException
* @throws \Bitrix\Main\SystemException
*/
public static function cleanActiveBasket(): array
{
if (!Loader::includeModule('sale')) {
return ['success' => false, 'error' => 'Module "sale" not installed'];
}
$basket = self::getUserBasket();
$removedItems = [];
$errors = [];
foreach ($basket as $item) {
if ($item->isDelay() || $item->getField('SUBSCRIBE') === 'Y') {
continue; // Пропускаем отложенные и подписки
}
$itemId = $item->getId();
$result = $item->delete();
if ($result->isSuccess()) {
$removedItems[] = $itemId;
} else {
$errors[] = implode(', ', $result->getErrorMessages());
}
}
$result = $basket->save();
if (!$result->isSuccess()) {
$errors = array_merge($errors, $result->getErrorMessages());
}
return [
'success' => empty($errors),
'removed_items' => $removedItems,
'errors' => $errors
];
}
/**
* Проверяет пуста ли корзина
*
* @return bool
*/
public static function isBasketEmpty(): bool
{
$basket = Basket::loadItemsForFUser(
Fuser::getId(),
SITE_ID
);
return $basket->count() === 0;
}
}
4. Интеграция с AJAX-контроллером
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
use Bitrix\Main\Engine\Controller;
class BasketController extends Controller
{
public function configureActions(): array
{
return [
'clean' => [
'prefilters' => [
new \Bitrix\Main\Engine\ActionFilter\Csrf(),
],
],
'check' => [
'prefilters' => [
new \Bitrix\Main\Engine\ActionFilter\Csrf(),
],
],
];
}
/**
* AJAX-действие для очистки корзины
*
* @return array
*/
public function cleanAction(): array
{
return BasketService::cleanActiveBasket();
}
/**
* Проверка состояния корзины
*
* @return array
*/
public function checkAction(): array
{
return [
'empty' => BasketService::isBasketEmpty(),
'count' => BasketService::getBasketItemsCount()
];
}
}
JavaScript для AJAX-вызова:
function cleanBasketViaAPI() {
BX.ajax.runComponentAction('vendor:component.name', 'clean', {
mode: 'ajax',
}).then(function (response) {
console.log(response);
// тут логика после удаления
}, function (response) {
// сюда будут приходить все ответы, у которых status !== 'success'
loader(false)
statusContainer.classList.add('_refused')
statusContainer.textContent = 'Ошибка запроса.'
console.log(response);
});
}
5. Особенности и лучшие практики
-
Безопасное удаление:
// Всегда проверяем контекст if (!$this->getCurrentUser()->isAuthorized()) { $this->error('Access denied'); } -
Обработка событий:
// После очистки корзины $event = new \Bitrix\Main\Event('sale', 'НужноеСобытиеКорзины'); $event->send(); -
Производительность:
// Пакетное сохранение вместо удаления по одному $basket->save(); // Один запрос вместо N -
Отложенные товары:
if ($item->isDelay()) { // Сохраняем для будущего использования } -
Логирование:
Bitrix\Main\Diag\Debug::writeToFile( "Basket cleared for user: {$userId}", 'INFO', 'basket.log' );
6. Тестирование и отладка
Юнит-тест для очистки корзины:
class BasketCleanTest extends \Bitrix\Main\Test\TestCase
{
public function testCleanBasket()
{
// Создаем тестовые товары
$basket = Basket::create(SITE_ID);
$item = $basket->addItem(...);
$basket->save();
// Очищаем корзину
$result = BasketService::cleanActiveBasket();
// Проверяем результат
$this->assertTrue($result['success']);
$this->assertEmpty(BasketService::getBasketItems());
}
}
7. Альтернативные сценарии
Очистка по расписанию:
// Агент для очистки неактивных корзин
function cleanInactiveBaskets()
{
$days = 30; // Период неактивности
$date = new \Bitrix\Main\Type\DateTime("-{$days} days");
$filter = [
'<=DATE_UPDATE' => $date,
'ORDER_ID' => 'null',
'LID' => SITE_ID
];
$res = \Bitrix\Sale\Basket::getList([
'filter' => $filter
]);
while ($basket = $res->fetchObject()) {
$basket->delete();
}
return "cleanInactiveBaskets();";
}
Миграция корзины:
// Перенос корзины при авторизации
AddEventHandler('main', 'OnAfterUserAuthorize', function($params) {
// https://dev.1c-bitrix.ru/community/forums/forum6/topic68560/
});
Заключение
Для корректной очистки корзины в Bitrix:
- Используйте D7 API - для новых проектов
- Фильтруйте отложенные товары - через
isDelay() - Применяйте пакетное сохранение - для оптимизации
- Реализуйте AJAX-интерфейс - для UX
- Тестируйте edge-case сценарии - пустая корзина, параллельные запросы
