构建销售模块:从服务重写到结账流程的实现
1. 服务重写
1.1 重写客户订单服务
在
src/Foggyline/SalesBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.php
文件中,将
// Override 'foggyline_customer.customer_orders'
注释替换为以下代码:
$container->removeDefinition
('foggyline_customer.customer_orders');
$container->setDefinition('foggyline_customer.customer_orders',
$container->getDefinition('foggyline_sales.customer_orders'));
这样可以使服务重写生效,并引入我们刚刚所做的所有更改。
1.2 重写畅销书服务
1.2.1 定义服务
在
src/Foggyline/SalesBundle/Resources/config/services.xml
文件的
service
元素下添加以下定义:
<service id="foggyline_sales.bestsellers"
class="Foggyline\SalesBundle\Service\BestSellers">
<argument type="service" id="doctrine.orm.entity_manager"/>
<argument type="service" id="router"/>
</service>
1.2.2 创建服务类
创建
src/Foggyline/SalesBundle/Service/BestSellers.php
文件,内容如下:
namespace Foggyline\SalesBundle\Service;
class BestSellers
{
private $em;
private $router;
public function __construct(
\Doctrine\ORM\EntityManager $entityManager,
\Symfony\Bundle\FrameworkBundle\Routing\Router $router
)
{
$this->em = $entityManager;
$this->router = $router;
}
public function getItems()
{
$products = array();
$salesOrderItem = $this->em->getRepository
('FoggylineSalesBundle:SalesOrderItem');
$_products = $salesOrderItem->getBestsellers();
foreach ($_products as $_product) {
$products[] = array(
'path' => $this->router->generate('product_show',
array('id' => $_product->getId())),
'name' => $_product->getTitle(),
'img' => $_product->getImage(),
'price' => $_product->getPrice(),
'id' => $_product->getId(),
);
}
return $products;
}
}
1.2.3 定义
getBestsellers
方法
在
src/Foggyline/SalesBundle/Repository/SalesOrderItemRepository.php
文件中添加
getBestsellers
方法:
public function getBestsellers()
{
$products = array();
$query = $this->_em->createQuery('SELECT IDENTITY(t.product),
SUM(t.qty) AS HIDDEN q
FROM Foggyline\SalesBundle\Entity
\SalesOrderItem t
GROUP BY t.product ORDER BY q DESC')
->setMaxResults(5);
$_products = $query->getResult();
foreach ($_products as $_product) {
$products[] = $this->_em->getRepository
('FoggylineCatalogBundle:Product')
->find(current($_product));
}
return $products;
}
1.2.4 完成服务重写
在
src/Foggyline/SalesBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.php
文件中,将
// Override 'bestsellers' service
注释替换为以下代码:
$container->removeDefinition('bestsellers');
$container->setDefinition('bestsellers', $container->
getDefinition('foggyline_sales.bestsellers'));
通过重写畅销书服务,我们为其他模块提供了基于实际销售的畅销书列表。
2. 创建购物车页面
2.1 编辑
indexAction
方法
在
CartController
中编辑
indexAction
方法:
public function indexAction()
{
if ($customer = $this->getUser()) {
$em = $this->getDoctrine()->getManager();
$cart = $em->getRepository('FoggylineSalesBundle:Cart')->
findOneBy(array('customer' => $customer));
$items = $cart->getItems();
$total = null;
foreach ($items as $item) {
$total += floatval($item->getQty() * $item->
getUnitPrice());
}
return $this->render('FoggylineSalesBundle:default:
cart/index.html.twig', array(
'customer' => $customer,
'items' => $items,
'total' => $total,
));
} else {
$this->addFlash('warning', 'Only logged in customers can
access cart page.');
return $this->redirectToRoute('foggyline_customer_login');
}
}
此方法检查用户是否登录,若登录则显示购物车中的所有商品,未登录则重定向到客户登录页面。
2.2 创建
index.html.twig
模板
创建
src/Foggyline/SalesBundle/Resources/views/Default/cart/index.html.twig
文件,内容如下:
{% extends 'base.html.twig' %}
{% block body %}
<h1>Shopping Cart</h1>
<div class="row">
<div class="large-8 columns">
<form action="{{ path('foggyline_sales_cart_update') }}"
method="post">
<table>
<thead>
<tr>
<th>Item</th>
<th>Price</th>
<th>Qty</th>
<th>Subtotal</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>{{ item.product.title }}</td>
<td>{{ item.unitPrice }}</td>
<td><input name="item[{{ item.id }}]" value="{{ item.qty
}}"/></td>
<td>{{ item.qty * item.unitPrice }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit" class="button">Update Cart</button>
</form>
</div>
<div class="large-4 columns">
<div>Order Total: {{ total }}</div>
<div><a href="{{ path('foggyline_sales_checkout') }}"
class="button">Go to Checkout</a></div>
</div>
</div>
{% endblock %}
模板会显示每个添加商品下的数量输入元素和“更新购物车”按钮,点击该按钮会提交表单到
foggyline_sales_cart_update
路由。
2.3 创建
foggyline_sales_cart_update
路由
在
src/Foggyline/SalesBundle/Resources/config/routing.xml
文件的
route
元素下添加以下条目:
<route id="foggyline_sales_cart_update" path="/cart/update">
<default key="_controller">FoggylineSalesBundle:Cart:update
</default>
</route>
2.4 实现
updateAction
方法
在
CartController
中添加
updateAction
方法:
public function updateAction(Request $request)
{
$items = $request->get('item');
$em = $this->getDoctrine()->getManager();
foreach ($items as $_id => $_qty) {
$cartItem = $em->getRepository
('FoggylineSalesBundle:CartItem')->find($_id);
if (intval($_qty) > 0) {
$cartItem->setQty($_qty);
$em->persist($cartItem);
} else {
$em->remove($cartItem);
}
}
// Persist to database
$em->flush();
$this->addFlash('success', 'Cart updated.');
return $this->redirectToRoute('foggyline_sales_cart');
}
若要从购物车中移除商品,只需将数量值设为 0 并点击“更新购物车”按钮。
3. 创建支付服务
3.1 替换注释代码
在
src/Foggyline/SalesBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.php
文件中,将
// Pickup/parse 'payment_method' services
注释替换为以下代码:
$container->getDefinition('foggyline_sales.payment')
->addArgument(
array_keys($container->findTaggedServiceIds
('payment_method'))
);
findTaggedServiceIds
方法返回所有标记为
payment_method
的服务的键值列表,并将其作为参数传递给
foggyline_sales.payment
服务。
3.2 编辑
services.xml
文件
在
src/Foggyline/SalesBundle/Resources/config/services.xml
文件的
service
元素下添加以下内容:
<service id="foggyline_sales.payment"
class="Foggyline\SalesBundle\Service\Payment">
<argument type="service" id="service_container"/>
</service>
3.3 创建
Payment
类
创建
src/Foggyline/SalesBundle/Service/Payment.php
文件,内容如下:
namespace Foggyline\SalesBundle\Service;
class Payment
{
private $container;
private $methods;
public function __construct($container, $methods)
{
$this->container = $container;
$this->methods = $methods;
}
public function getAvailableMethods()
{
$methods = array();
foreach ($this->methods as $_method) {
$methods[] = $this->container->get($_method);
}
return $methods;
}
}
该服务接受两个参数
$container
和
$methods
,
getAvailableMethods
方法能够返回所有标记为
payment_method
的服务。
4. 创建运输服务
4.1 替换注释代码
在
src/Foggyline/SalesBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.php
文件中,将
// Pickup/parse shipment_method' services
注释替换为以下代码:
$container->getDefinition('foggyline_sales.shipment')
->addArgument(
array_keys($container->findTaggedServiceIds
('shipment_method'))
);
4.2 编辑
services.xml
文件
在
src/Foggyline/SalesBundle/Resources/config/services.xml
文件的
service
元素下添加以下内容:
<service id="foggyline_sales.shipment"
class="Foggyline\SalesBundle\Service\Payment">
<argument type="service" id="service_container"/>
</service>
4.3 创建
Shipment
类
创建
src/Foggyline/SalesBundle/Service/Shipment.php
文件,内容如下:
namespace Foggyline\SalesBundle\Service;
class Shipment
{
private $container;
private $methods;
public function __construct($container, $methods)
{
$this->container = $container;
$this->methods = $methods;
}
public function getAvailableMethods()
{
$methods = array();
foreach ($this->methods as $_method) {
$methods[] = $this->container->get($_method);
}
return $methods;
}
}
通过统一的支付和运输服务,我们能够获取所有支付和运输服务,使结账过程更加便捷。
5. 创建结账页面
5.1 编辑
indexAction
方法
在
CheckoutController
中编辑
indexAction
方法:
public function indexAction()
{
if ($customer = $this->getUser()) {
$form = $this->getAddressForm();
$em = $this->getDoctrine()->getManager();
$cart = $em->getRepository('FoggylineSalesBundle:Cart')
->findOneBy(array('customer' => $customer));
$items = $cart->getItems();
$total = null;
foreach ($items as $item) {
$total += floatval($item->getQty() * $item->getUnitPrice());
}
return $this->render
('FoggylineSalesBundle:default:checkout/index.html.twig',
array(
'customer' => $customer,
'items' => $items,
'cart_subtotal' => $total,
'shipping_address_form' => $form->createView(),
'shipping_methods' => $this->get
('foggyline_sales.shipment')->getAvailableMethods()
));
} else {
$this->addFlash('warning', 'Only logged in customers can
access checkout page.');
return $this->redirectToRoute('foggyline_customer_login');
}
}
private function getAddressForm()
{
return $this->createFormBuilder()
->add('address_first_name', TextType::class)
->add('address_last_name', TextType::class)
->add('company', TextType::class)
->add('address_telephone', TextType::class)
->add('address_country', CountryType::class)
->add('address_state', TextType::class)
->add('address_city', TextType::class)
->add('address_postcode', TextType::class)
->add('address_street', TextType::class)
->getForm();
}
此方法获取当前登录客户的购物车,并将其传递到
checkout/index.html.twig
模板,同时还会传递运输步骤所需的其他变量。
5.2 创建
index.html.twig
模板
创建
src/Foggyline/SalesBundle/Resources/views/Default/checkout/index.html.twig
文件,内容如下:
{% extends 'base.html.twig' %}
{% block body %}
<h1>Checkout</h1>
<div class="row">
<div class="large-8 columns">
<form action="{{ path('foggyline_sales_checkout_payment') }}"
method="post" id="shipping_form">
<fieldset>
<legend>Shipping Address</legend>
{{ form_widget(shipping_address_form) }}
</fieldset>
<fieldset>
<legend>Shipping Methods</legend>
<ul>
{% for method in shipping_methods %}
{% set shipment = method.getInfo('street', 'city',
'country', 'postcode', 'amount', 'qty')['shipment'] %}
<li>
<label>{{ shipment.title }}</label>
<ul>
{% for delivery_option in shipment.delivery_options %}
<li>
<input type="radio" name="shipment_method"
value="{{ shipment.code }}____
{{ delivery_option.code }}____
{{ delivery_option.price }}">
{{ delivery_option.title }}
({{ delivery_option.price }})
<br>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</fieldset>
</form>
</div>
<div class="large-4 columns">
{% include
'FoggylineSalesBundle:default:checkout/order_sumarry.html.twig'
%}
<div>Cart Subtotal: {{ cart_subtotal }}</div>
<div><a id="shipping_form_submit" href="#"
class="button">Next</a>
</div>
</div>
</div>
<script type="text/javascript">
var form = document.getElementById('shipping_form');
document.getElementById('shipping_form_submit')
.addEventListener('click', function () {
form.submit();
});
</script>
{% endblock %}
模板会列出所有与地址相关的表单字段和可用的运输方法,点击“下一步”按钮会将表单提交到
foggyline_sales_checkout_payment
路由。
5.3 定义
foggyline_sales_checkout_payment
路由
在
src/Foggyline/SalesBundle/Resources/config/routing.xml
文件的
routes
元素下添加以下条目:
<route id="foggyline_sales_checkout_payment"
path="/checkout/payment">
<default
key="_controller">FoggylineSalesBundle:Checkout:payment</default>
</route>
5.4 实现
paymentAction
方法
在
CheckoutController
中添加
paymentAction
方法:
public function paymentAction(Request $request)
{
$addressForm = $this->getAddressForm();
$addressForm->handleRequest($request);
if ($addressForm->isSubmitted() && $addressForm->isValid() &&
$customer = $this->getUser()) {
$em = $this->getDoctrine()->getManager();
$cart = $em->getRepository('FoggylineSalesBundle:Cart')->
findOneBy(array('customer' => $customer));
$items = $cart->getItems();
$cartSubtotal = null;
foreach ($items as $item) {
$cartSubtotal += floatval($item->getQty() * $item->
getUnitPrice());
}
$shipmentMethod = $_POST['shipment_method'];
$shipmentMethod = explode('____', $shipmentMethod);
$shipmentMethodCode = $shipmentMethod[0];
$shipmentMethodDeliveryCode = $shipmentMethod[1];
$shipmentMethodDeliveryPrice = $shipmentMethod[2];
// Store relevant info into session
$checkoutInfo = $addressForm->getData();
$checkoutInfo['shipment_method'] = $shipmentMethodCode .
'____' . $shipmentMethodDeliveryCode;
$checkoutInfo['shipment_price'] =
$shipmentMethodDeliveryPrice;
$checkoutInfo['items_price'] = $cartSubtotal;
$checkoutInfo['total_price'] = $cartSubtotal +
$shipmentMethodDeliveryPrice;
$this->get('session')->set('checkoutInfo', $checkoutInfo);
return $this->render('FoggylineSalesBundle:default:
checkout/payment.html.twig', array(
'customer' => $customer,
'items' => $items,
'cart_subtotal' => $cartSubtotal,
'delivery_subtotal' => $shipmentMethodDeliveryPrice,
'delivery_label' =>'Delivery Label Here',
'order_total' => $cartSubtotal +
$shipmentMethodDeliveryPrice,
'payment_methods' => $this->get
('foggyline_sales.payment')->getAvailableMethods()
));
} else {
$this->addFlash('warning', 'Only logged in customers can
access checkout page.');
return $this->redirectToRoute('foggyline_customer_login');
}
}
该方法获取结账过程运输步骤的提交内容,将相关值存储到会话中,获取支付步骤所需的变量,并渲染
checkout/payment.html.twig
模板。
5.5 创建
payment.html.twig
模板
创建
src/Foggyline/SalesBundle/Resources/views/Default/checkout/payment.html.twig
文件,内容如下:
{% extends 'base.html.twig' %}
{% block body %}
<h1>Checkout</h1>
<div class="row">
<div class="large-8 columns">
<form action="{{ path('foggyline_sales_checkout_process') }}"
method="post" id="payment_form">
<fieldset>
<legend>Payment Methods</legend>
<ul>
{% for method in payment_methods %}
{% set payment = method.getInfo()['payment'] %}
<li>
<input type="radio" name="payment_method"
value="{{ payment.code }}"> {{ payment.title }}
{% if payment['form'] is defined %}
<div id="{{ payment.code }}_form">
{{ form_widget(payment['form']) }}
</div>
{% endif %}
</li>
{% endfor %}
</ul>
</fieldset>
</form>
</div>
<div class="large-4 columns">
{% include 'FoggylineSalesBundle:default:checkout/
order_sumarry.html.twig' %}
<div>Cart Subtotal: {{ cart_subtotal }}</div>
<div>{{ delivery_label }}: {{ delivery_subtotal }}</div>
<div>Order Total: {{ order_total }}</div>
<div><a id="payment_form_submit" href="#" class="button">Place
Order</a>
</div>
</div>
</div>
<script type="text/javascript">
var form = document.getElementById('payment_form');
document.getElementById('payment_form_submit').
addEventListener('click', function () {
form.submit();
});
</script>
{% endblock %}
该模板会渲染可用的支付方法和“下单”按钮,点击该按钮会将 POST 请求提交到
foggyline_sales_checkout_process
路由。
5.6 定义
foggyline_sales_checkout_process
路由
在
src/Foggyline/SalesBundle/Resources/config/routing.xml
文件的
routes
元素下添加以下条目:
<route id="foggyline_sales_checkout_process"
path="/checkout/process">
<default
key="_controller">FoggylineSalesBundle:Checkout:process</default>
</route>
5.7 实现
processAction
方法
在
CheckoutController
中添加
processAction
方法:
public function processAction()
{
if ($customer = $this->getUser()) {
$em = $this->getDoctrine()->getManager();
// Merge all the checkout info, for SalesOrder
$checkoutInfo = $this->get('session')->get
('checkoutInfo');
$now = new \DateTime();
// Create Sales Order
$salesOrder = new \Foggyline\SalesBundle\Entity
\SalesOrder();
$salesOrder->setCustomer($customer);
$salesOrder->setItemsPrice($checkoutInfo['items_price']);
$salesOrder->setShipmentPrice
($checkoutInfo['shipment_price']);
$salesOrder->setTotalPrice($checkoutInfo['total_price']);
$salesOrder->setPaymentMethod($_POST['payment_method']);
$salesOrder->setShipmentMethod
($checkoutInfo['shipment_method']);
$salesOrder->setCreatedAt($now);
$salesOrder->setModifiedAt($now);
$salesOrder->setCustomerEmail($customer->getEmail());
$salesOrder->setCustomerFirstName
($customer->getFirstName());
$salesOrder->setCustomerLastName
($customer->getLastName());
$salesOrder->setAddressFirstName
($checkoutInfo['address_first_name']);
$salesOrder->setAddressLastName
($checkoutInfo['address_last_name']);
$salesOrder->setAddressCountry
($checkoutInfo['address_country']);
$salesOrder->setAddressState
($checkoutInfo['address_state']);
$salesOrder->setAddressCity
($checkoutInfo['address_city']);
$salesOrder->setAddressPostcode
($checkoutInfo['address_postcode']);
$salesOrder->setAddressStreet
($checkoutInfo['address_street']);
$salesOrder->setAddressTelephone
($checkoutInfo['address_telephone']);
$salesOrder->setStatus(\Foggyline\SalesBundle\Entity\
SalesOrder::STATUS_PROCESSING);
$em->persist($salesOrder);
$em->flush();
// Foreach cart item, create order item, and delete cart
item
$cart = $em->getRepository('FoggylineSalesBundle:Cart')->
findOneBy(array('customer' => $customer));
$items = $cart->getItems();
foreach ($items as $item) {
$orderItem = new \Foggyline\SalesBundle\Entity
\SalesOrderItem();
$orderItem->setSalesOrder($salesOrder);
$orderItem->setTitle($item->getProduct()->getTitle());
$orderItem->setQty($item->getQty());
$orderItem->setUnitPrice($item->getUnitPrice());
$orderItem->setTotalPrice($item->getQty() * $item-
>getUnitPrice());
$orderItem->setModifiedAt($now);
$orderItem->setCreatedAt($now);
$orderItem->setProduct($item->getProduct());
$em->persist($orderItem);
$em->remove($item);
}
$em->remove($cart);
$em->flush();
$this->get('session')->set('last_order', $salesOrder->
getId());
return $this->redirectToRoute
('foggyline_sales_checkout_success');
} else {
$this->addFlash('warning', 'Only logged in customers can
access checkout page.');
return $this->redirectToRoute('foggyline_customer_login');
}
}
当 POST 请求到达控制器时,会创建一个新订单及所有相关商品,同时清空购物车和购物车商品,最后将客户重定向到订单成功页面。
6. 创建订单成功页面
6.1 定义路由
在
src/Foggyline/SalesBundle/Resources/config/routing.xml
文件的
routes
元素下添加以下条目:
<route id="foggyline_sales_checkout_success"
path="/checkout/success">
<default
key="_controller">FoggylineSalesBundle:Checkout:success</default>
</route>
6.2 实现
successAction
方法
在
CheckoutController
中添加
successAction
方法:
public function successAction()
{
return $this->render('FoggylineSalesBundle:default:
checkout/success.html.twig', array(
'last_order' => $this->get('session')->get('last_order')
));
}
6.3 创建
success.html.twig
模板
创建
src/Foggyline/SalesBundle/Resources/views/Default/checkout/success.html.twig
文件,内容如下:
{% extends 'base.html.twig' %}
{% block body %}
<h1>Checkout Success</h1>
<div class="row">
<p>Thank you for placing your order #{{ last_order }}.</p>
<p>You can see order details <a href="{{
path('customer_account') }}">here</a>.</p>
</div>
{% endblock %}
至此,我们完成了网店的整个结账流程,为更强大的实现奠定了基础。
7. 创建商店经理仪表盘
7.1 创建控制器
创建
src/AppBundle/Controller/StoreManagerController.php
文件,内容如下:
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class StoreManagerController extends Controller
{
/**
* @Route("/store_manager", name="store_manager")
*/
public function indexAction()
{
return $this->render
('AppBundle:default:store_manager.html.twig');
}
}
7.2 创建模板
创建
src/AppBundle/Resources/views/default/store_manager.html.twig
文件,内容如下:
{% extends 'base.html.twig' %}
{% block body %}
<h1>Store Manager</h1>
<div class="row">
<div class="large-6 columns">
<div class="stacked button-group">
<a href="{{ path('category_new') }}" class="button">Add new
Category</a>
<a href="{{ path('product_new') }}" class="button">Add new
Product</a>
<a href="{{ path('customer_new') }}" class="button">Add new
Customer</a>
</div>
</div>
<div class="large-6 columns">
<div class="stacked button-group">
<a href="{{ path('category_index') }}" class="button">List &
Manage Categories</a>
<a href="{{ path('product_index') }}" class="button">List &
Manage Products</a>
<a href="{{ path('customer_index') }}" class="button">List &
Manage Customers</a>
</div>
</div>
</div>
{% endblock %}
这个仪表盘为商店经理提供了添加和管理类别、产品和客户的功能。
总结
通过以上步骤,我们完成了销售模块的构建,包括服务重写、购物车页面、支付和运输服务、结账页面、订单成功页面以及商店经理仪表盘的创建。这个简单的实现为后续更复杂的功能扩展奠定了基础。
流程图
graph LR
A[开始] --> B[服务重写]
B --> C[创建购物车页面]
C --> D[创建支付服务]
D --> E[创建运输服务]
E --> F[创建结账页面]
F --> G[创建订单成功页面]
G --> H[创建商店经理仪表盘]
H --> I[结束]
表格
| 功能模块 | 相关文件 | 主要方法 |
|---|---|---|
| 服务重写 |
OverrideServiceCompilerPass.php
|
removeDefinition
、
setDefinition
|
| 购物车页面 |
CartController.php
、
index.html.twig
|
indexAction
、
updateAction
|
| 支付服务 |
Payment.php
、
services.xml
|
getAvailableMethods
|
| 运输服务 |
Shipment.php
、
services.xml
|
getAvailableMethods
|
| 结账页面 |
CheckoutController.php
、
index.html.twig
、
payment.html.twig
|
indexAction
、
paymentAction
、
processAction
|
| 订单成功页面 |
CheckoutController.php
、
success.html.twig
|
successAction
|
| 商店经理仪表盘 |
StoreManagerController.php
、
store_manager.html.twig
|
indexAction
|
构建销售模块:从服务重写到结账流程的实现
8. 功能模块总结与分析
8.1 服务重写
服务重写是整个销售模块的基础,它允许我们根据实际需求对现有的服务进行定制。通过重写客户订单服务和畅销书服务,我们能够确保系统使用最新的业务逻辑。例如,在重写畅销书服务时,我们从数据库中获取实际的销售数据,而不是使用虚拟数据,这使得显示的畅销书列表更加真实和有价值。
8.2 购物车页面
购物车页面是用户与系统交互的重要环节。它提供了一个直观的界面,让用户可以查看和管理自己的购物车内容。通过
indexAction
方法,我们可以根据用户的登录状态显示不同的页面。如果用户已登录,将显示购物车中的商品和总价;如果用户未登录,则会重定向到登录页面。
updateAction
方法则允许用户更新购物车中的商品数量,甚至移除商品。
8.3 支付和运输服务
支付和运输服务的创建使得结账过程更加灵活和可扩展。通过统一的服务,我们可以轻松地集成不同的支付和运输方式。例如,在
Payment
类和
Shipment
类中,
getAvailableMethods
方法可以返回所有可用的支付和运输服务,这使得用户可以根据自己的需求进行选择。
8.4 结账页面
结账页面是整个销售流程的核心。它分为两个步骤:运输信息收集和支付信息收集。在运输信息收集步骤中,用户需要填写收货地址和选择运输方式;在支付信息收集步骤中,用户需要选择支付方式并提交订单。通过
indexAction
、
paymentAction
和
processAction
方法,我们可以确保整个结账过程的顺利进行。
8.5 订单成功页面
订单成功页面是用户完成购物后的反馈页面。它不仅可以感谢用户的购买,还可以提供订单详情和相关的购物建议。通过
successAction
方法,我们可以将最后创建的订单 ID 传递给模板,让用户可以查看订单详情。
8.6 商店经理仪表盘
商店经理仪表盘为商店管理人员提供了一个便捷的管理界面。通过该界面,管理人员可以添加和管理类别、产品和客户。
indexAction
方法返回的模板中包含了各种管理按钮,方便管理人员进行操作。
9. 代码优化建议
9.1 错误处理
在现有的代码中,错误处理相对较少。例如,在
processAction
方法中,如果数据库操作失败,没有相应的错误处理机制。建议在关键的数据库操作和表单处理中添加错误处理代码,以提高系统的稳定性。
9.2 代码复用
部分代码存在重复的情况,例如在计算购物车总价的代码在多个方法中出现。建议将这些重复的代码提取到一个公共的方法中,以提高代码的复用性。
9.3 性能优化
在查询畅销书列表时,使用了 DQL 查询。可以考虑对数据库进行优化,例如添加索引,以提高查询性能。同时,在处理大量数据时,可以考虑使用分页技术,以减少内存占用。
10. 未来功能扩展
10.1 优惠券系统
可以添加优惠券系统,让用户在结账时可以使用优惠券享受折扣。这需要在数据库中添加优惠券表,并在结账过程中进行相应的处理。
10.2 订单跟踪系统
为用户提供订单跟踪功能,让用户可以实时了解订单的状态。这需要在数据库中添加订单状态表,并在相关的控制器和模板中进行相应的处理。
10.3 多语言支持
为了满足不同地区用户的需求,可以添加多语言支持。这需要在模板和控制器中进行相应的国际化处理。
11. 总结
通过以上步骤,我们完成了一个简单的销售模块的构建。从服务重写、购物车页面的创建到结账流程的实现,再到商店经理仪表盘的搭建,每个环节都紧密相连,构成了一个完整的销售系统。虽然目前的系统还比较简单,但它为后续的功能扩展提供了良好的基础。在未来的开发中,我们可以根据实际需求添加更多的功能,如优惠券系统、订单跟踪系统等,以提高系统的实用性和用户体验。
流程图
graph LR
A[服务重写] --> B[购物车页面]
B --> C[支付和运输服务]
C --> D[结账页面]
D --> E[订单成功页面]
E --> F[商店经理仪表盘]
F --> G[代码优化]
G --> H[未来功能扩展]
表格
| 优化建议 | 具体内容 | 涉及文件 |
|---|---|---|
| 错误处理 | 在关键数据库操作和表单处理中添加错误处理代码 | 多个控制器文件 |
| 代码复用 | 提取重复代码到公共方法 | 多个控制器文件 |
| 性能优化 | 对数据库添加索引,使用分页技术 | 数据库相关文件 |
通过以上的总结和分析,我们可以更好地理解整个销售模块的构建过程,并为后续的开发和优化提供参考。希望这些内容对大家有所帮助。
超级会员免费看
1048

被折叠的 条评论
为什么被折叠?



