Magento 2 创建 REST API

Magento 2.x 创建API:

1. 配置 xml:
file: app/code/Oneday/Common/etc/webapi.xml

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
    <route url="/V1/checkout/navs" method="POST">
        <service class="Oneday\Common\Api\Checkout\NavsManagementInterface" method="getList"/>
        <resources>
            <resource ref="anonymous"/>
        </resources>
    </route>
</routes>

此 API 对应的 URL 是 /rest/default/V1/checkout/navs

file: app/code/Oneday/Common/etc/di.xml

1
2
3
4
5
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Oneday\Common\Api\Checkout\NavsManagementInterface" type="Oneday\Common\Model\Checkout\NavsManagement" />
    <preference for="Oneday\Common\Api\Data\Checkout\NavsInterface" type="Oneday\Common\Model\Checkout\Navs" />
</config>

2. 创建 di.xml 中对应的 4 个 php 文件, 分别有 2 个 interface, 和 2 个 class.

分别为:

1
interface Oneday\Common\Api\Data\Checkout\NavsInterface
1
class Oneday\Common\Model\Checkout\Navs implements Oneday\Common\Api\Data\Checkout\NavsInterface
1
interface Oneday\Common\Api\Checkout\NavsManagementInterface
1
class Oneday\Common\Model\Checkout\NavsManagement implements \Oneday\Common\Api\Checkout\NavsManagementInterface

其中, class Oneday\Common\Model\Checkout\NavsManagement 是 API 执行者, class Oneday\Common\Model\Checkout\Navs 是 API response 载体

file: app/code/Oneday/Common/Api/Checkout/NavsManagementInterface.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

namespace Oneday\Common\Api\Checkout;


interface NavsManagementInterface
{
    /**
     * @return \Oneday\Common\Api\Data\Checkout\NavsInterface
     */
    public function getList();
}

file: app/code/Oneday/Common/Model/Checkout/NavsManagement.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<?php

namespace Oneday\Common\Model\Checkout;


class NavsManagement implements \Oneday\Common\Api\Checkout\NavsManagementInterface
{
    protected $scopeConfig;
    protected $priceHelper;
    protected $shippingHelper;
    protected $session;
    protected $objectManager;
    protected $dataFactory;

    protected $extraDiscountRules;


    public function __construct(
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Framework\Pricing\Helper\Data $priceHelper,
        \Oneday\Shipping\Helper\Data $shippingHelper,
        \Magento\Checkout\Model\Session $session,
        \Magento\Framework\ObjectManagerInterface $objectManager,
        \Oneday\Common\Api\Data\Checkout\NavsInterfaceFactory $dataFactory
    ) {
        $this->scopeConfig = $scopeConfig;
        $this->priceHelper = $priceHelper;
        $this->shippingHelper = $shippingHelper;
        $this->session = $session;
        $this->objectManager = $objectManager;
        $this->dataFactory = $dataFactory;
        return $this;
    }

    public function getList()
    {
        /** @var \Oneday\Common\Api\Data\Checkout\NavsInterface $res */
        $res = $this->dataFactory->create();
        $res->setShippingTip($this->getFreeShippingTip())
            ->setDiscountTip($this->getDiscountTip());

        return $res;
    }

    protected function getQuote()
    {
        return $this->session->getQuote();
    }


    public function getFreeShippingTip()
    {
        $quote = $this->getQuote();
        $countryId = $quote->getShippingAddress()->getCountryId();

        $setting = $this->shippingHelper->loadFreeShippingSetting($countryId);
        $allowMethods = [];     // allow free shipping methods
        foreach ($setting as $methodCode => $item) {
            if ($item['free_shipping_over'] && $item['apply_free_shipping']) {
                $allowMethods[] = $methodCode;
            }
        }

        $freeShippingOver = [
            'tablerate_bestway' => [
                'value' => $this->scopeConfig->getValue('carriers/tablerate/free_shipping_over'),
                'name'  => __(''),
            ],
            'accelerate_standard' => [
                'value' => $this->scopeConfig->getValue('carriers/accelerate/free_shipping_over'),
                'name'  => __('STANDARD'),
            ],
            'expedite_expedite' => [
                'value' => $this->scopeConfig->getValue('carriers/expedite/free_shipping_over'),
                'name'  => __('EXPRESS'),
            ],
        ];

        $baseSpread = 0;
        $name = '';
        $baseSubtotalWithDiscount = (float) $quote->getBaseSubtotalWithDiscount();

        foreach ($freeShippingOver as $key => $method) {
            if (!in_array($key, $allowMethods)) {
                continue;
            }
            $value = (float) $method['value'];
            if ($baseSubtotalWithDiscount < $value) {
                $baseSpread = $value - $baseSubtotalWithDiscount;
                $name = __($method['name']);
                break;
            }
        }

        if ($baseSpread > 0.01) {
            $spread = $this->priceHelper->currency($baseSpread, true, false);
            return sprintf(__('Spend <span class="price">%s</span> more to enjoy FREE %s SHIPPING'), $spread, $name);
        }
        return '';
    }

    public function getDiscountTip()
    {
        $quote = $this->getQuote();
        $baseSubtotal = (float) $quote->getBaseSubtotal();

        $nextDiscountPercentage = 0;
        $baseSpread = 0;
        $currentPercentage = 0;

        $extraDiscountRules = $this->_getExtraDiscountRules();
        foreach ($extraDiscountRules as $key => $extraDiscountRule) {
            if ($extraDiscountRule['low_price'] <= $baseSubtotal) {
                $currentPercentage = $extraDiscountRule['discount_percentage'];
                $highPrice = $extraDiscountRule['high_price'];
                if ($highPrice > 0.01 && $highPrice > $baseSubtotal) {
                    $baseSpread = $highPrice - $baseSubtotal;
                }

                if (isset($extraDiscountRules[$key + 1])) {
                    $nextDiscountPercentage = $extraDiscountRules[$key + 1]['discount_percentage'];
                }
            }
        }

        $tip = '';

        if ($currentPercentage) {
            $tip .= sprintf(__('You have already enjoyed EXTRA %s%% discount. '), $currentPercentage);
        }

        if ($baseSpread && $nextDiscountPercentage) {
            $spread = $this->priceHelper->currency($baseSpread, true, false);
            $tip .= sprintf(__(' Spend <span class="price">%s</span> more to enjoy Extra %s%% discount.'), $spread, $nextDiscountPercentage);
        }
        return $tip;
    }

    protected function _getExtraDiscountRules()
    {
        if ($this->extraDiscountRules === null) {
            $rules = explode(';', $this->scopeConfig->getValue('promotion/extra_discount/rule'));
            $this->extraDiscountRules = [];
            if (count($rules)) {
                foreach ($rules as $rule) {
                    $_rule = explode('|', $rule);
                    if (count($_rule) === 2) {
                        $priceRange = explode('~', $_rule[0]);
                        $discountPercentage = $_rule[1];

                        if (count($priceRange) === 2 && $discountPercentage > 0) {
                            $this->extraDiscountRules[] = [
                                'low_price' => (float) $priceRange[0],
                                'high_price'=> (float) $priceRange[1],
                                'discount_percentage' => (int) $discountPercentage,
                            ];
                        }

                    }
                }
            }
        }
        return $this->extraDiscountRules;
    }
}

file: app/code/Oneday/Common/Api/Data/Checkout/NavsInterface.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php

namespace Oneday\Common\Api\Data\Checkout;

interface NavsInterface
{

    /**
     * @return mixed
     */
    public function getShippingTip();

    /**
     * @return NavsInterface
     */
    public function setShippingTip($tip);

    /**
     * @return mixed
     */
    public function getDiscountTip();

    /**
     * @return NavsInterface
     */
    public function setDiscountTip($tip);

}

file: app/code/Oneday/Common/Model/Checkout/Navs.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

namespace Oneday\Common\Model\Checkout;

use Magento\Framework\DataObject;
use Oneday\Common\Api\Data\Checkout\NavsInterface;

class Navs extends DataObject implements NavsInterface
{
    public function getShippingTip()
    {
        return $this->getData('shipping_tip');
    }

    public function setShippingTip($tip)
    {
        return $this->setData('shipping_tip', $tip);
    }

    public function getDiscountTip()
    {
        return $this->getData('discount_tip');
    }

    public function setDiscountTip($tip)
    {
        return $this->setData('discount_tip', $tip);
    }
}

创建好上面的这些文件后, 刷新 Magento 的缓存

1
php bin/magento cache:clean

调用 /rest/default/V1/checkout/navs 就会返回对应的数据了