Completed
Push — master ( c6b5de...db50e7 )
by Dmitry
04:45
created

src/cart/BatchPurchaseStrategy.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Finance module for HiPanel
4
 *
5
 * @link      https://github.com/hiqdev/hipanel-module-finance
6
 * @package   hipanel-module-finance
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2019, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hipanel\modules\finance\cart;
12
13
use hiqdev\hiart\ResponseErrorException;
14
use hiqdev\yii2\cart\ShoppingCart;
15
use Yii;
16
use yii\base\InvalidParamException;
17
18
/**
19
 * Class BatchPurchaseStrategy purchases positions in batch.
20
 *
21
 * @author Dmytro Naumenko <[email protected]>
22
 */
23
class BatchPurchaseStrategy implements PurchaseStrategyInterface
24
{
25
    use PurchaseResultTrait;
26
27
    /**
28
     * @var AbstractCartPosition[]
29
     */
30
    protected $positions = [];
31
32
    /**
33
     * @var ShoppingCart
34
     */
35
    protected $cart;
36
37
    /**
38
     * @var AbstractPurchase[]
39
     */
40
    protected $purchases;
41
42
    /**
43
     * BatchPurchaseStrategy constructor.
44
     *
45
     * @param ShoppingCart $cart
46
     */
47
    public function __construct(ShoppingCart $cart)
48
    {
49
        $this->cart = $cart;
50
    }
51
52
    /** {@inheritdoc} */
53
    public function addPosition(AbstractCartPosition $position)
54
    {
55
        $this->positions[$position->getId()] = $position;
56
        $this->ensureConsistency();
57
    }
58
59
    /** {@inheritdoc} */
60
    public function run()
61
    {
62
        $this->resetPurchaseResults();
63
        $this->createPurchaseObjects();
64
        if (empty($this->purchases)) {
65
            return;
66
        }
67
68
        $samplePurchase = reset($this->purchases);
69
        $operation = $samplePurchase::operation();
70
71
        try {
72
            $response = $samplePurchase::perform($operation, $this->collectData(), ['batch' => true]);
73
            $this->analyzeResponse($response);
74
        } catch (ResponseErrorException $e) {
75
            $this->extractResultsFromException($e);
76
        }
77
    }
78
79
    private function createPurchaseObjects()
80
    {
81
        foreach ($this->positions as $id => $position) {
82
            $this->purchases[$id] = $position->getPurchaseModel();
83
        }
84
    }
85
86
    private function collectData()
87
    {
88
        $result = [];
89
        foreach ($this->purchases as $id => $purchase) {
90
            if (!$purchase->validate()) {
91
                Yii::error('Failed to validate purchase: ' . reset($purchase->getFirstErrors()), __METHOD__);
92
                $this->error[] = new ErrorPurchaseException('Failed to validate purchase. Contact support.', $purchase);
93
                continue;
94
            }
95
96
            $result[$id] = $purchase->getAttributes();
97
        }
98
99
        return $result;
100
    }
101
102
    private function extractResultsFromException(ResponseErrorException $e)
103
    {
104
        $data = $e->getResponse()->getData();
105
106
        if (!is_array($data)) {
107
            Yii::error('Abnormal response during purchase', __METHOD__);
108
            throw $e;
109
        }
110
111
        $this->analyzeResponse($data);
112
    }
113
114
    protected function analyzeResponse($response)
115
    {
116
        foreach ($response as $key => $item) {
117
            $this->analyzeResponseItem($key, $item);
118
        }
119
    }
120
121
    protected function analyzeResponseItem($key, $data)
122
    {
123
        if (!isset($this->purchases[$key])) {
124
            return;
125
        }
126
127
        $purchase = $this->purchases[$key];
128
        if ($error = $this->getPurchaseErrorFromResponse($purchase, $data)) {
129
            $this->error[] = new ErrorPurchaseException($error, $purchase);
130
        } elseif ($pendingMessage = $this->getPurchasePendingFromResponse($purchase, $data)) {
131
            $this->pending[] = new PendingPurchaseException($pendingMessage, $purchase);
132
        } else {
133
            $this->success[] = $purchase;
134
        }
135
    }
136
137
    /**
138
     * @param AbstractPurchase $purchase
139
     * @param array $data
140
     * @return string|null Error message or `null` when no errors found
141
     */
142
    protected function getPurchaseErrorFromResponse(AbstractPurchase $purchase, $data)
0 ignored issues
show
The parameter $purchase is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
143
    {
144
        if (is_array($data) && array_key_exists('_error', $data)) {
145
            return $data['_error'];
146
        }
147
148
        return null;
149
    }
150
151
    /**
152
     * Override this method to detect pending purchase result.
153
     *
154
     * @param AbstractPurchase $purchase
155
     * @param array $data
156
     * @return string|null Pending reason or `null` when no errors found
157
     */
158
    protected function getPurchasePendingFromResponse(AbstractPurchase $purchase, $data)
0 ignored issues
show
The parameter $purchase is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
159
    {
160
        return null;
161
    }
162
163
    protected function ensureConsistency()
164
    {
165
        $class = null;
166
        foreach ($this->positions as $id => $position) {
167
            if ($class === null) {
168
                $class = get_class($position);
169
            }
170
171
            if (!$position instanceof $class) {
172
                throw new InvalidParamException('Position "' . $id . '" is violates position class consistency policy');
173
            }
174
        }
175
    }
176
}
177