Skip to content

Commit

Permalink
feature #10688 MVP of the debug cart panel (, pamil)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.8-dev branch.

Discussion
----------

| Q               | A
| --------------- | -----
| Branch?         |  master
| Bug fix?        | no
| New feature?    | yes
| BC breaks?      | no
| Deprecations?   | no
| License         | MIT

Why? Sometimes, you want to debug what was inside of the cart on a specific request. While on shop pages you will see the cart summary widget, you do not know the details (id, ids and codes of products/variants), etc. This is useful when debugging promotions, taxes, etc. This is an MVP done during a hackathon, but can be extended with more data and details, especially about $.

<img width="1425" alt="Screenshot 2019-09-21 at 16 54 08" src="https://user-images.githubusercontent.com/614970/65375028-0ee88980-dc91-11e9-9b3d-ac9a089b9757.png">
<img width="288" alt="Screenshot 2019-09-21 at 16 54 11" src="https://user-images.githubusercontent.com/614970/65375029-0ee88980-dc91-11e9-9f8c-bbc69894453e.png">
<img width="582" alt="Sylius___Your_shopping_cart" src="https://user-images.githubusercontent.com/614970/65375030-0ee88980-dc91-11e9-88c9-4f4b439d2855.png">



Commits
-------

587581d MVP of the debug cart panel
0f81c57 Improve cart collector
  • Loading branch information
lchrusciel committed May 20, 2020
2 parents ac83adc + 0f81c57 commit 552c4a0
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 0 deletions.
134 changes: 134 additions & 0 deletions src/Sylius/Bundle/CoreBundle/Collector/CartCollector.php
@@ -0,0 +1,134 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\CoreBundle\Collector;

use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\OrderItemInterface;
use Sylius\Component\Order\Context\CartContextInterface;
use Sylius\Component\Order\Context\CartNotFoundException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;

/**
* @internal
*/
final class CartCollector extends DataCollector
{
/** @var CartContextInterface */
private $cartContext;

public function __construct(CartContextInterface $cartContext)
{
$this->cartContext = $cartContext;
$this->data = [];
}

public function hasCart(): bool
{
return $this->data !== [];
}

public function getId(): ?int
{
return $this->data['id'];
}

public function getTotal(): ?int
{
return $this->data['total'];
}

public function getSubtotal(): ?int
{
return $this->data['subtotal'];
}

public function getCurrency(): ?string
{
return $this->data['currency'];
}

public function getLocale(): ?string
{
return $this->data['locale'];
}

public function getQuantity(): ?int
{
return $this->data['quantity'];
}

public function getItems(): ?array
{
return $this->data['items'];
}

public function getStates(): ?array
{
return $this->data['states'];
}

public function collect(Request $request, Response $response, \Exception $exception = null): void
{
try {
/** @var OrderInterface $cart */
$cart = $this->cartContext->getCart();

$itemsData = $cart->getItems()->map(static function (OrderItemInterface $item): array {
$variant = $item->getVariant();
$product = $variant->getProduct();

return [
'id' => $item->getId(),
'variantName' => $variant->getName(),
'variantId' => $variant->getId(),
'variantCode' => $variant->getCode(),
'quantity' => $item->getQuantity(),
'productName' => $product->getName(),
'productCode' => $product->getCode(),
'productId' => $product->getId(),
];
})->toArray();

$this->data = [
'id' => $cart->getId(),
'total' => $cart->getTotal(),
'subtotal' => $cart->getItemsTotal(),
'currency' => $cart->getCurrencyCode(),
'locale' => $cart->getLocaleCode(),
'quantity' => count($cart->getItems()),
'items' => $itemsData,
'states' => [
'main' => $cart->getState(),
'checkout' => $cart->getCheckoutState(),
'shipping' => $cart->getShippingState(),
'payment' => $cart->getPaymentState(),
]
];
} catch (CartNotFoundException $exception) {
$this->data = [];
}
}

public function reset(): void
{
$this->data = [];
}

public function getName(): string
{
return 'sylius_cart';
}
}
5 changes: 5 additions & 0 deletions src/Sylius/Bundle/CoreBundle/Resources/config/services.xml
Expand Up @@ -72,6 +72,11 @@
<tag name="data_collector" template="@SyliusCore/Collector/sylius.html.twig" id="sylius_core" priority="-512" />
</service>

<service id="Sylius\Bundle\CoreBundle\Collector\CartCollector" public="false">
<argument type="service" id="sylius.context.cart" />
<tag name="data_collector" template="@SyliusCore/Collector/cart.html.twig" id="sylius_cart" priority="-512" />
</service>

<service id="sylius.shipping_methods_resolver.zones_and_channel_based" class="Sylius\Component\Core\Resolver\ZoneAndChannelBasedShippingMethodsResolver">
<argument type="service" id="sylius.repository.shipping_method" />
<argument type="service" id="sylius.zone_matcher" />
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
108 changes: 108 additions & 0 deletions src/Sylius/Bundle/CoreBundle/Resources/views/Collector/cart.html.twig
@@ -0,0 +1,108 @@
{% extends '@WebProfiler/Profiler/layout.html.twig' %}

{% block toolbar %}
{% if collector.hasCart %}
{% import "@SyliusShop/Common/Macro/money.html.twig" as money %}

{% set icon %}
{{ include('@SyliusCore/Collector/Icon/cart.svg') }}
<span class="sf-toolbar-value">{{ collector.quantity|default(0) }}</span>
{% endset %}

{% set text %}
<div class="sf-toolbar-info-group">
<div class="sf-toolbar-info-piece">
<b>ID</b>
<span>{{ collector.id }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Subtotal</b>
<span>{{ money.convertAndFormat(collector.subtotal, collector.currency) }}</span>
</div>
<div class="sf-toolbar-info-piece">
<b>Total</b>
<span>{{ money.convertAndFormat(collector.total, collector.currency) }}</span>
</div>
</div>
<div class="sf-toolbar-info-group">
<div class="sf-toolbar-info-piece">
<span><a href="{{ profiler_url ~ '?panel=sylius_cart' }}" rel="help">View details</a></span>
</div>
</div>
{% endset %}

{% include '@WebProfiler/Profiler/toolbar_item.html.twig' with {'link': profiler_url} %}
{% endif %}
{% endblock %}

{% block menu %}
{% if collector.hasCart %}
<span class="label {% if collector.quantity|default(0) == 0 %}disabled{% endif %}">
<span class="icon">{{ include('@SyliusCore/Collector/Icon/cart.svg') }}</span>
<strong>Cart</strong>
<span class="count">
<span>{{ collector.quantity|default(0) }}</span>
</span>
</span>
{% endif %}
{% endblock %}

{% block panel %}
{% if collector.hasCart %}
{% import "@SyliusShop/Common/Macro/money.html.twig" as money %}

<h2>Cart</h2>
<table>
<tr>
<th>ID</th>
<th>Currency</th>
<th>Locale</th>
<th>Subtotal</th>
<th>Total</th>
</tr>
<tr>
<td>{{ collector.id }}</td>
<td>{{ collector.currency }}</td>
<td>{{ collector.locale }}</td>
<td>{{ money.convertAndFormat(collector.subtotal, collector.currency) }}</td>
<td>{{ money.convertAndFormat(collector.total, collector.currency) }}</td>
</tr>
</table>

<h2>States</h2>
<table>
<tr>
<th>Main</th>
<th>Checkout</th>
<th>Shipping</th>
<th>Payment</th>
</tr>
<tr>
<td>{{ collector.states.main }}</td>
<td>{{ collector.states.checkout }}</td>
<td>{{ collector.states.shipping }}</td>
<td>{{ collector.states.payment }}</td>
</tr>
</table>

{% if collector.items|length > 0 %}
<h2>Items</h2>
<table>
<tr>
<th>ID</th>
<th>Product (Code, ID)</th>
<th>Variant (Code, ID)</th>
<th>Quantity</th>
</tr>
{% for item in collector.items %}
<tr>
<td>{{ item.id }}</td>
<td>{{ item.productName }} ({{ item.productCode }}, {{ item.productId }})</td>
<td>{{ item.variantName }} ({{ item.variantCode }}, {{ item.variantId }})</td>
<td>{{ item.quantity }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% endif %}
{% endblock %}

0 comments on commit 552c4a0

Please sign in to comment.