PluginProbe
Packeta / 1.2.2
Packeta v1.2.2
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / src / Packetery / Module / Carrier / OptionsPage.php

OptionsPage.php in Packeta 1.2.2, at src/Packetery/Module/Carrier/OptionsPage.php

426 lines 11.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class OptionsPage
4 *
5 * @package Packetery\Options
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module\Carrier;
11
12 use Packetery\Module\Checkout;
13 use Packetery\Module\FormFactory;
14 use Packetery\Module\MessageManager;
15 use PacketeryLatte\Engine;
16 use PacketeryNette\Forms\Container;
17 use PacketeryNette\Forms\Form;
18 use PacketeryNette\Http\Request;
19
20 /**
21 * Class OptionsPage
22 *
23 * @package Packetery\Options
24 */
25 class OptionsPage {
26
27 public const FORM_FIELD_NAME = 'name';
28 public const SLUG = 'packeta-country';
29
30 /**
31 * PacketeryLatte_engine.
32 *
33 * @var Engine PacketeryLatte engine.
34 */
35 private $latteEngine;
36
37 /**
38 * Carrier repository.
39 *
40 * @var Repository Carrier repository.
41 */
42 private $carrierRepository;
43
44 /**
45 * Form factory.
46 *
47 * @var FormFactory Form factory.
48 */
49 private $formFactory;
50
51 /**
52 * PacketeryNette Request.
53 *
54 * @var Request PacketeryNette Request.
55 */
56 private $httpRequest;
57
58 /**
59 * CountryListingPage.
60 *
61 * @var CountryListingPage CountryListingPage.
62 */
63 private $countryListingPage;
64
65 /**
66 * Message manager.
67 *
68 * @var MessageManager
69 */
70 private $messageManager;
71
72 /**
73 * Plugin constructor.
74 *
75 * @param Engine $latteEngine PacketeryLatte_engine.
76 * @param Repository $carrierRepository Carrier repository.
77 * @param FormFactory $formFactory Form factory.
78 * @param Request $httpRequest PacketeryNette Request.
79 * @param CountryListingPage $countryListingPage CountryListingPage.
80 * @param MessageManager $messageManager Message manager.
81 */
82 public function __construct(
83 Engine $latteEngine,
84 Repository $carrierRepository,
85 FormFactory $formFactory,
86 Request $httpRequest,
87 CountryListingPage $countryListingPage,
88 MessageManager $messageManager
89 ) {
90 $this->latteEngine = $latteEngine;
91 $this->carrierRepository = $carrierRepository;
92 $this->formFactory = $formFactory;
93 $this->httpRequest = $httpRequest;
94 $this->countryListingPage = $countryListingPage;
95 $this->messageManager = $messageManager;
96 }
97
98 /**
99 * Registers WP callbacks.
100 */
101 public function register(): void {
102 add_submenu_page(
103 \Packetery\Module\Options\Page::SLUG,
104 __( 'Carrier settings', 'packetery' ),
105 __( 'Carrier settings', 'packetery' ),
106 'manage_options',
107 self::SLUG,
108 array(
109 $this,
110 'render',
111 ),
112 10
113 );
114 }
115
116 /**
117 * Creates settings form.
118 *
119 * @param array $carrierData Carrier data.
120 *
121 * @return Form
122 */
123 private function createForm( array $carrierData ): Form {
124 $optionId = Checkout::CARRIER_PREFIX . $carrierData['id'];
125
126 $form = $this->formFactory->create( $optionId );
127
128 $form->addCheckbox(
129 'active',
130 __( 'Active carrier', 'packetery' ) . ':'
131 );
132
133 $form->addText( self::FORM_FIELD_NAME, __( 'Display name', 'packetery' ) . ':' )
134 ->setRequired();
135
136 $weightLimits = $form->addContainer( 'weight_limits' );
137 if ( empty( $carrierData['weight_limits'] ) ) {
138 $this->addWeightLimit( $weightLimits, 0 );
139 } else {
140 foreach ( $carrierData['weight_limits'] as $index => $limit ) {
141 $this->addWeightLimit( $weightLimits, $index );
142 }
143 }
144
145 $form->addText( 'default_COD_surcharge', __( 'defaultCODSurchargeLabel', 'packetery' ) . ':' )
146 ->setRequired( false )
147 ->addRule( Form::FLOAT )
148 ->addRule( Form::MIN, null, 0 );
149
150 $surchargeLimits = $form->addContainer( 'surcharge_limits' );
151 if ( ! empty( $carrierData['surcharge_limits'] ) ) {
152 foreach ( $carrierData['surcharge_limits'] as $index => $limit ) {
153 $this->addSurchargeLimit( $surchargeLimits, $index );
154 }
155 }
156
157 $item = $form->addText( 'free_shipping_limit', __( 'Free shipping limit', 'packetery' ) . ':' );
158 $item->addRule( $form::FLOAT, __( 'Please enter a valid decimal number.', 'packetery' ) );
159 $form->addHidden( 'id' )->setRequired();
160 $form->addSubmit( 'save' );
161
162 $carrier = $this->carrierRepository->getById( (int) $carrierData['id'] );
163 if ( $carrier && false === $carrier->hasPickupPoints() ) {
164 $addressValidationOptions = [
165 'none' => __( 'noAddressValidation', 'packetery' ),
166 'optional' => __( 'optionalAddressValidation', 'packetery' ),
167 'required' => __( 'requiredAddressValidation', 'packetery' ),
168 ];
169 $form->addSelect( 'address_validation', __( 'addressValidation', 'packetery' ) . ':', $addressValidationOptions )
170 ->setDefaultValue( 'none' );
171 }
172
173 $form->onValidate[] = [ $this, 'validateOptions' ];
174 $form->onSuccess[] = [ $this, 'updateOptions' ];
175
176 $carrierOptions = get_option( $optionId );
177 $carrierOptions['id'] = $carrierData['id'];
178 if ( empty( $carrierOptions[ self::FORM_FIELD_NAME ] ) ) {
179 $carrierOptions[ self::FORM_FIELD_NAME ] = $carrierData['name'];
180 }
181 $form->setDefaults( $carrierOptions );
182
183 return $form;
184 }
185
186 /**
187 * Creates settings form.
188 *
189 * @param array $carrierData Carrier data.
190 *
191 * @return Form
192 */
193 private function createFormTemplate( array $carrierData ): Form {
194 $optionId = Checkout::CARRIER_PREFIX . $carrierData['id'];
195
196 $form = $this->formFactory->create( $optionId . '_template' );
197
198 $weightLimitsTemplate = $form->addContainer( 'weight_limits' );
199 $this->addWeightLimit( $weightLimitsTemplate, 0 );
200
201 $surchargeLimitsTemplate = $form->addContainer( 'surcharge_limits' );
202 $this->addSurchargeLimit( $surchargeLimitsTemplate, 0 );
203
204 return $form;
205 }
206
207 /**
208 * Validates options.
209 *
210 * @param Form $form Form.
211 */
212 public function validateOptions( Form $form ): void {
213 if ( $form->hasErrors() ) {
214 add_settings_error( '', '', esc_attr( __( 'someCarrierDataAreInvalid', 'packetery' ) ) );
215 return;
216 }
217
218 $options = $form->getValues( 'array' );
219
220 $this->checkOverlapping(
221 $form,
222 $options,
223 'weight_limits',
224 'weight',
225 __( 'Weight rules are overlapping, fix it please.', 'packetery' )
226 );
227 $this->checkOverlapping(
228 $form,
229 $options,
230 'surcharge_limits',
231 'order_price',
232 __( 'Surcharge rules are overlapping, fix it please.', 'packetery' )
233 );
234 }
235
236 /**
237 * Saves carrier options. onSuccess callback.
238 *
239 * @param Form $form Form.
240 *
241 * @return void
242 */
243 public function updateOptions( Form $form ): void {
244 $options = $form->getValues( 'array' );
245
246 $options = $this->mergeNewLimits( $options, 'weight_limits' );
247 $options = $this->sortLimits( $options, 'weight_limits', 'weight' );
248 $options = $this->mergeNewLimits( $options, 'surcharge_limits' );
249 $options = $this->sortLimits( $options, 'surcharge_limits', 'order_price' );
250
251 update_option( Checkout::CARRIER_PREFIX . $options['id'], $options );
252 $this->messageManager->flash_message( __( 'settingsSaved', 'packetery' ), MessageManager::TYPE_SUCCESS, MessageManager::RENDERER_PACKETERY, 'carrier-country' );
253
254 if ( wp_safe_redirect(
255 add_query_arg(
256 [
257 'page' => self::SLUG,
258 'code' => $this->httpRequest->getQuery( 'code' ),
259 ],
260 get_admin_url( null, 'admin.php' )
261 ),
262 303
263 ) ) {
264 exit;
265 }
266 }
267
268 /**
269 * Renders page.
270 */
271 public function render(): void {
272 $countryIso = $this->httpRequest->getQuery( 'code' );
273 if ( $countryIso ) {
274 $countryCarriers = $this->carrierRepository->getByCountryIncludingZpoints( $countryIso );
275 $carriersData = [];
276 $post = $this->httpRequest->getPost();
277 foreach ( $countryCarriers as $carrier ) {
278 if ( ! empty( $post ) && $post['id'] === $carrier->getId() ) {
279 $formTemplate = $this->createFormTemplate( $post );
280 $form = $this->createForm( $post );
281 if ( $form->isSubmitted() ) {
282 $form->fireEvents();
283 }
284 } else {
285 $carrierData = $carrier->__toArray();
286 $options = get_option( Checkout::CARRIER_PREFIX . $carrier->getId() );
287 if ( false !== $options ) {
288 $carrierData += $options;
289 }
290 $formTemplate = $this->createFormTemplate( $carrierData );
291 $form = $this->createForm( $carrierData );
292 }
293
294 $carriersData[] = [
295 'form' => $form,
296 'formTemplate' => $formTemplate,
297 'carrier' => $carrier,
298 ];
299 }
300
301 $this->latteEngine->render(
302 PACKETERY_PLUGIN_DIR . '/template/carrier/country.latte',
303 [
304 'forms' => $carriersData,
305 'country_iso' => $countryIso,
306 'globalCurrency' => get_woocommerce_currency_symbol(),
307 'flashMessages' => $this->messageManager->renderToString( MessageManager::RENDERER_PACKETERY, 'carrier-country' ),
308 ]
309 );
310 } else {
311 $this->countryListingPage->render();
312 }
313 }
314
315 /**
316 * Transforms new_ keys to common numeric.
317 *
318 * @param array $options Options to merge.
319 * @param string $limitsContainer Container id.
320 *
321 * @return array
322 */
323 private function mergeNewLimits( array $options, string $limitsContainer ): array {
324 $newOptions = [];
325 if ( isset( $options[ $limitsContainer ] ) ) {
326 foreach ( $options[ $limitsContainer ] as $key => $option ) {
327 if ( is_int( $key ) ) {
328 $newOptions[ $key ] = $option;
329 }
330 if ( 0 === strpos( (string) $key, 'new_' ) ) {
331 $newOptions[] = $option;
332 }
333 }
334 $options[ $limitsContainer ] = $newOptions;
335 }
336
337 return $options;
338 }
339
340 /**
341 * Checks rules overlapping.
342 *
343 * @param Form $form Form.
344 * @param array $options Form data.
345 * @param string $limitsContainer Container id.
346 * @param string $limitKey Rule id.
347 * @param string $overlappingMessage Error message.
348 *
349 * @return void
350 */
351 private function checkOverlapping( Form $form, array $options, string $limitsContainer, string $limitKey, string $overlappingMessage ): void {
352 $limits = array_column( $options[ $limitsContainer ], $limitKey );
353 if ( count( array_unique( $limits, SORT_NUMERIC ) ) !== count( $limits ) ) {
354 add_settings_error( $limitsContainer, $limitsContainer, esc_attr( $overlappingMessage ) );
355 $form->addError( $overlappingMessage );
356 }
357 }
358
359 /**
360 * Sorts rules.
361 *
362 * @param array $options Form data.
363 * @param string $limitsContainer Container id.
364 * @param string $limitKey Rule id.
365 *
366 * @return array
367 */
368 private function sortLimits( array $options, string $limitsContainer, string $limitKey ): array {
369 $limits = array_column( $options[ $limitsContainer ], $limitKey );
370 array_multisort( $limits, SORT_ASC, $options[ $limitsContainer ] );
371
372 return $options;
373 }
374
375 /**
376 * Adds limit fields to form.
377 *
378 * @param Container $weightLimits Container.
379 * @param int|string $index Index.
380 *
381 * @return void
382 */
383 private function addWeightLimit( Container $weightLimits, $index ): void {
384 $limit = $weightLimits->addContainer( (string) $index );
385 $item = $limit->addText( 'weight', __( 'Weight up to', 'packetery' ) . ':' );
386 $item->setRequired();
387 $item->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packetery' ) );
388 $item->addRule( Form::MIN, null, 0 );
389 $item->addCondition( Form::MAX, 0 )
390 ->addCondition( Form::MIN, 0 )
391 // translators: %d is the value.
392 ->addRule( Form::BLANK, __( 'valueMustNotBe%d', 'packetery' ), 0 );
393
394 $item = $limit->addText( 'price', __( 'Price', 'packetery' ) . ':' );
395 $item->setRequired();
396 $item->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packetery' ) );
397 $item->addRule( Form::MIN, null, 0 );
398 }
399
400 /**
401 * Adds limit fields to form.
402 *
403 * @param Container $surchargeLimits Container.
404 * @param int|string $index Index.
405 *
406 * @return void
407 */
408 private function addSurchargeLimit( Container $surchargeLimits, $index ): void {
409 $limit = $surchargeLimits->addContainer( (string) $index );
410 $item = $limit->addText( 'order_price', __( 'Order price up to', 'packetery' ) . ':' );
411 $item->setRequired();
412 $item->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packetery' ) );
413 $item->addRule( Form::MIN, null, 0 );
414 $item->addCondition( Form::MAX, 0 )
415 ->addCondition( Form::MIN, 0 )
416 // translators: %d is the value.
417 ->addRule( Form::BLANK, __( 'valueMustNotBe%d', 'packetery' ), 0 );
418
419 $item = $limit->addText( 'surcharge', __( 'Surcharge', 'packetery' ) . ':' );
420 $item->setRequired();
421 $item->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packetery' ) );
422 $item->addRule( Form::MIN, null, 0 );
423 }
424
425 }
426