This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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 | use yii\web\User; |
||
18 | |||
19 | /** |
||
20 | * Class BatchPurchaseStrategy purchases positions in batch. |
||
21 | * |
||
22 | * @author Dmytro Naumenko <[email protected]> |
||
23 | */ |
||
24 | class BatchPurchaseStrategy implements PurchaseStrategyInterface |
||
25 | { |
||
26 | use PurchaseResultTrait; |
||
27 | |||
28 | /** |
||
29 | * @var AbstractCartPosition[] |
||
30 | */ |
||
31 | protected $positions = []; |
||
32 | |||
33 | /** |
||
34 | * @var ShoppingCart |
||
35 | */ |
||
36 | protected $cart; |
||
37 | |||
38 | /** |
||
39 | * @var AbstractPurchase[] |
||
40 | */ |
||
41 | protected $purchases; |
||
42 | /** |
||
43 | * @var User |
||
44 | */ |
||
45 | private $user; |
||
46 | |||
47 | /** |
||
48 | * BatchPurchaseStrategy constructor. |
||
49 | * |
||
50 | * @param ShoppingCart $cart |
||
51 | */ |
||
52 | public function __construct(ShoppingCart $cart, User $user) |
||
53 | { |
||
54 | $this->cart = $cart; |
||
55 | $this->user = $user; |
||
56 | } |
||
57 | |||
58 | /** {@inheritdoc} */ |
||
59 | public function addPosition(AbstractCartPosition $position) |
||
60 | { |
||
61 | $this->positions[$position->getId()] = $position; |
||
62 | $this->ensureConsistency(); |
||
63 | } |
||
64 | |||
65 | /** {@inheritdoc} */ |
||
66 | public function run() |
||
67 | { |
||
68 | $this->resetPurchaseResults(); |
||
69 | $this->createPurchaseObjects(); |
||
70 | if (empty($this->purchases)) { |
||
71 | return; |
||
72 | } |
||
73 | |||
74 | $samplePurchase = reset($this->purchases); |
||
75 | $operation = $samplePurchase::operation(); |
||
76 | |||
77 | try { |
||
78 | $response = $samplePurchase::perform($operation, $this->collectData(), ['batch' => true]); |
||
79 | $this->analyzeResponse($response); |
||
80 | } catch (ResponseErrorException $e) { |
||
81 | $this->extractResultsFromException($e); |
||
82 | } |
||
83 | } |
||
84 | |||
85 | private function createPurchaseObjects() |
||
86 | { |
||
87 | foreach ($this->positions as $id => $position) { |
||
88 | $this->purchases[$id] = $position->getPurchaseModel(); |
||
89 | } |
||
90 | } |
||
91 | |||
92 | private function collectData() |
||
93 | { |
||
94 | $result = []; |
||
95 | foreach ($this->purchases as $id => $purchase) { |
||
96 | if (!$purchase->validate()) { |
||
97 | Yii::error('Failed to validate purchase: ' . reset($purchase->getFirstErrors()), __METHOD__); |
||
98 | $this->error[] = new ErrorPurchaseException('Failed to validate purchase. Contact support.', $purchase); |
||
99 | continue; |
||
100 | } |
||
101 | |||
102 | $result[$id] = $purchase->getAttributes(); |
||
103 | } |
||
104 | |||
105 | return $result; |
||
106 | } |
||
107 | |||
108 | private function extractResultsFromException(ResponseErrorException $e) |
||
109 | { |
||
110 | $data = $e->getResponse()->getData(); |
||
111 | |||
112 | if (!is_array($data)) { |
||
113 | Yii::error('Abnormal response during purchase', __METHOD__); |
||
114 | throw $e; |
||
115 | } |
||
116 | |||
117 | $this->analyzeResponse($data); |
||
118 | } |
||
119 | |||
120 | protected function analyzeResponse($response) |
||
121 | { |
||
122 | if ($response['_error'] === 'not enough money') { |
||
123 | foreach ($this->purchases as $key => $purchase) { |
||
124 | $error = Yii::t('hipanel:finance', 'Insufficient funds on the balance'); |
||
125 | if ($this->user->can('support')) { |
||
126 | $error = Yii::t('hipanel:finance', 'Insufficient funds. Maybe, your client does not have enough money on balance?'); |
||
127 | } |
||
128 | |||
129 | $this->error[] = new ErrorPurchaseException($error, $purchase); |
||
130 | } |
||
131 | } |
||
132 | |||
133 | foreach ($response as $key => $item) { |
||
134 | $this->analyzeResponseItem($key, $item); |
||
135 | } |
||
136 | } |
||
137 | |||
138 | protected function analyzeResponseItem($key, $data) |
||
139 | { |
||
140 | if (!isset($this->purchases[$key])) { |
||
141 | return; |
||
142 | } |
||
143 | |||
144 | $purchase = $this->purchases[$key]; |
||
145 | if ($error = $this->getPurchaseErrorFromResponse($purchase, $data)) { |
||
146 | $this->error[] = new ErrorPurchaseException($error, $purchase); |
||
147 | } elseif ($pendingMessage = $this->getPurchasePendingFromResponse($purchase, $data)) { |
||
148 | $this->pending[] = new PendingPurchaseException($pendingMessage, $purchase); |
||
149 | } else { |
||
150 | $this->success[] = $purchase; |
||
151 | } |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * @param AbstractPurchase $purchase |
||
156 | * @param array $data |
||
157 | * @return string|null Error message or `null` when no errors found |
||
158 | */ |
||
159 | protected function getPurchaseErrorFromResponse(AbstractPurchase $purchase, $data) |
||
0 ignored issues
–
show
|
|||
160 | { |
||
161 | if (is_array($data) && array_key_exists('_error', $data)) { |
||
162 | return $data['_error']; |
||
163 | } |
||
164 | |||
165 | return null; |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Override this method to detect pending purchase result. |
||
170 | * |
||
171 | * @param AbstractPurchase $purchase |
||
172 | * @param array $data |
||
173 | * @return string|null Pending reason or `null` when no errors found |
||
174 | */ |
||
175 | protected function getPurchasePendingFromResponse(AbstractPurchase $purchase, $data) |
||
0 ignored issues
–
show
|
|||
176 | { |
||
177 | return null; |
||
178 | } |
||
179 | |||
180 | protected function ensureConsistency() |
||
181 | { |
||
182 | $class = null; |
||
183 | foreach ($this->positions as $id => $position) { |
||
184 | if ($class === null) { |
||
185 | $class = get_class($position); |
||
186 | } |
||
187 | |||
188 | if (!$position instanceof $class) { |
||
189 | throw new InvalidParamException('Position "' . $id . '" is violates position class consistency policy'); |
||
190 | } |
||
191 | } |
||
192 | } |
||
193 | } |
||
194 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.