PluginProbe
Packeta / 1.2.6
Packeta v1.2.6
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.6, at src/Packetery/Module/Carrier/OptionsPage.php

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