FlexiCart provides a flexible cart merging system that allows you to merge one cart into another. This is particularly useful for merging guest carts with user carts when a user logs in.
use Daikazu\Flexicart\Cart;
// Merge source cart into target cart
$targetCart->mergeFrom($sourceCart);
// Or merge by cart ID (requires database storage)
$targetCart->mergeFrom('source-cart-id');
FlexiCart supports four built-in merge strategies that control how items and conditions are merged:
Adds quantities together when the same item exists in both carts. Source attributes win, and conditions are combined.
$targetCart->mergeFrom($sourceCart, 'sum');
| Aspect | Behavior |
|---|---|
| Quantity | Target + Source |
| Attributes | Source wins |
| Item Conditions | Combined (source overrides same-named) |
| Cart Conditions | Combined (source overrides same-named) |
Example:
// Target has: Widget (qty: 2)
// Source has: Widget (qty: 3)
// Result: Widget (qty: 5)
Source completely replaces target. Useful when you want the source cart to take precedence.
$targetCart->mergeFrom($sourceCart, 'replace');
| Aspect | Behavior |
|---|---|
| Quantity | Source |
| Attributes | Source |
| Item Conditions | Source |
| Cart Conditions | Source |
Keeps the highest quantity. Source attributes win, and conditions are combined.
$targetCart->mergeFrom($sourceCart, 'max');
| Aspect | Behavior |
|---|---|
| Quantity | Max of Target and Source |
| Attributes | Source wins |
| Item Conditions | Combined |
| Cart Conditions | Combined |
Example:
// Target has: Widget (qty: 5)
// Source has: Widget (qty: 3)
// Result: Widget (qty: 5)
Keeps target values for existing items. Only adds items that don't exist in the target.
$targetCart->mergeFrom($sourceCart, 'keep_target');
| Aspect | Behavior |
|---|---|
| Quantity | Target (for existing items) |
| Attributes | Target (for existing items) |
| Item Conditions | Target |
| Cart Conditions | Target |
Configure default merge behavior in config/flexicart.php:
'merge' => [
// Default merge strategy: 'sum', 'replace', 'max', 'keep_target'
'default_strategy' => env('CART_MERGE_STRATEGY', 'sum'),
// Whether to clear the source cart after merging
'delete_source' => env('CART_MERGE_DELETE_SOURCE', true),
],
You can also pass a strategy object instead of a string:
use Daikazu\Flexicart\Strategies\MaxMergeStrategy;
$targetCart->mergeFrom($sourceCart, new MaxMergeStrategy());
You can create custom merge strategies by implementing MergeStrategyInterface:
namespace App\Strategies;
use Daikazu\Flexicart\CartItem;
use Daikazu\Flexicart\Conditions\Contracts\ConditionInterface;
use Daikazu\Flexicart\Strategies\MergeStrategyInterface;
use Illuminate\Support\Collection;
class CustomMergeStrategy implements MergeStrategyInterface
{
public function name(): string
{
return 'custom';
}
public function mergeItem(CartItem $targetItem, CartItem $sourceItem): array
{
// Return merged item data array
return [
'id' => $targetItem->id,
'name' => $sourceItem->name,
'price' => $sourceItem->unitPrice(),
'quantity' => $targetItem->quantity + $sourceItem->quantity,
'taxable' => $sourceItem->taxable,
'attributes' => $sourceItem->attributes->toArray(),
];
}
public function handleNewItem(CartItem $sourceItem): array
{
return [
'id' => $sourceItem->id,
'name' => $sourceItem->name,
'price' => $sourceItem->unitPrice(),
'quantity' => $sourceItem->quantity,
'taxable' => $sourceItem->taxable,
'attributes' => $sourceItem->attributes->toArray(),
];
}
public function mergeConditions(Collection $targetConditions, Collection $sourceConditions): Collection
{
// Return merged conditions collection
return $targetConditions->merge($sourceConditions);
}
}
Register your custom strategy:
use Daikazu\Flexicart\Strategies\MergeStrategyFactory;
MergeStrategyFactory::register('custom', CustomMergeStrategy::class);
// Now you can use it
$targetCart->mergeFrom($sourceCart, 'custom');
When carts are merged, a CartMerged event is dispatched:
use Daikazu\Flexicart\Events\CartMerged;
Event::listen(CartMerged::class, function (CartMerged $event) {
Log::info("Cart merged", [
'target_cart_id' => $event->cartId,
'source_cart_id' => $event->sourceCartId,
'merged_items_count' => $event->mergedItems->count(),
'strategy' => $event->strategy,
]);
});
| Property | Type | Description |
|---|---|---|
cartId |
string | The target cart ID |
sourceCartId |
string | The source cart ID that was merged |
mergedItems |
Collection | Items that were merged/added |
strategy |
string | The merge strategy name used |
occurredAt |
DateTimeImmutable | When the merge occurred |
// When user logs in
public function handleLogin(Request $request)
{
$user = Auth::user();
$guestCartId = session('guest_cart_id');
if ($guestCartId) {
$userCart = Cart::getCartById($user->cart_id);
$userCart->mergeFrom($guestCartId, 'sum');
session()->forget('guest_cart_id');
}
}
// Convert wishlist to cart
$cart->mergeFrom($wishlistCart, 'keep_target');
// Restore abandoned cart
$currentCart->mergeFrom($abandonedCart, 'max');
| Strategy | Best For |
|---|---|
sum |
Combining carts where you want all quantities |
replace |
Source should override everything |
max |
Keeping the larger quantity |
keep_target |
Preserving target, only adding new items |
use Daikazu\Flexicart\Exceptions\CartException;
try {
$targetCart->mergeFrom('invalid-cart-id');
} catch (CartException $e) {
// Source cart not found
Log::error($e->getMessage());
}
Get a list of available merge strategies:
use Daikazu\Flexicart\Strategies\MergeStrategyFactory;
$strategies = MergeStrategyFactory::available();
// ['sum', 'replace', 'max', 'keep_target']
How can I help you explore Laravel packages today?