PluginProbe
Packeta / trunk
Packeta vtrunk
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 / Shipping / ShippingProvider.php

ShippingProvider.php in Packeta trunk, at src/Packetery/Module/Shipping/ShippingProvider.php

243 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare( strict_types=1 );
4
5 namespace Packetery\Module\Shipping;
6
7 use Packetery\Core\Entity\Carrier;
8 use Packetery\Module\Carrier\CarDeliveryConfig;
9 use Packetery\Module\Carrier\CarrierOptionsFactory;
10 use Packetery\Module\Carrier\EntityRepository;
11 use Packetery\Module\ContextResolver;
12 use Packetery\Module\ShippingMethod;
13 use Packetery\Module\ShippingZoneRepository;
14 use WC_Abstract_Order;
15
16 class ShippingProvider {
17 /**
18 * @var array<int, array<string, string>>
19 */
20 private static $sortedMethodsCache = [];
21
22 /**
23 * @var CarDeliveryConfig
24 */
25 private $carDeliveryConfig;
26
27 /**
28 * @var ContextResolver
29 */
30 private $contextResolver;
31
32 /**
33 * @var ShippingZoneRepository
34 */
35 private $shippingZoneRepository;
36
37 /**
38 * @var EntityRepository
39 */
40 private $carrierRepository;
41
42 /**
43 * @var CarrierOptionsFactory
44 */
45 private $carrierOptionsFactory;
46
47 public function __construct(
48 CarDeliveryConfig $carDeliveryConfig,
49 ContextResolver $contextResolver,
50 ShippingZoneRepository $shippingZoneRepository,
51 EntityRepository $carrierRepository,
52 CarrierOptionsFactory $carrierOptionsFactory
53 ) {
54 $this->carDeliveryConfig = $carDeliveryConfig;
55 $this->contextResolver = $contextResolver;
56 $this->shippingZoneRepository = $shippingZoneRepository;
57 $this->carrierRepository = $carrierRepository;
58 $this->carrierOptionsFactory = $carrierOptionsFactory;
59 }
60
61 /**
62 * Loads generated shipping methods, including split ones when split is off.
63 * Used in CLI generator.
64 */
65 public static function loadAllClasses(): void {
66 $generatedClassesPath = __DIR__ . '/Generated';
67 foreach ( scandir( $generatedClassesPath ) as $filename ) {
68 if ( preg_match( '/\.php$/', $filename ) ) {
69 require_once $generatedClassesPath . '/' . $filename;
70 }
71 }
72 }
73
74 /**
75 * Loads generated shipping methods.
76 */
77 public function loadClasses(): void {
78 $generatedClassesPath = __DIR__ . '/Generated';
79 foreach ( scandir( $generatedClassesPath ) as $filename ) {
80 if ( ! preg_match( '/\.php$/', $filename ) ) {
81 continue;
82 }
83 if ( $this->carDeliveryConfig->isDisabled() ) {
84 $carDeliveryIds = implode( '|', Carrier::CAR_DELIVERY_CARRIERS );
85 if ( preg_match( '/^ShippingMethod_(' . $carDeliveryIds . ')\.php$/', $filename ) ) {
86 continue;
87 }
88 }
89 require_once $generatedClassesPath . '/' . $filename;
90 }
91 }
92
93 /**
94 * Gets all full classnames of generated shipping methods.
95 */
96 private function getGeneratedClassnames(): array {
97 $namespace = __NAMESPACE__ . '\Generated';
98
99 return array_filter(
100 get_declared_classes(),
101 function ( $fullyQualifiedClassname ) use ( $namespace ) {
102 return strpos( $fullyQualifiedClassname, $namespace ) === 0;
103 }
104 );
105 }
106
107 public static function wcOrderHasOurMethod( WC_Abstract_Order $wcOrder ): bool {
108 foreach ( $wcOrder->get_shipping_methods() as $shippingMethod ) {
109 if ( self::isPacketaMethod( $shippingMethod->get_method_id() ) ) {
110 return true;
111 }
112 }
113
114 return false;
115 }
116
117 /**
118 * Checks if provided shipping method id belongs to one of Packeta methods.
119 */
120 public static function isPacketaMethod( string $methodId ): bool {
121 return (
122 $methodId === ShippingMethod::PACKETERY_METHOD_ID ||
123 strpos( $methodId, BaseShippingMethod::PACKETA_METHOD_PREFIX ) === 0
124 );
125 }
126
127 /**
128 * Loads shipping methods, uses different approach for zone setting page.
129 *
130 * @param array<string, string> $methods Previous state.
131 *
132 * @return array<string, string>
133 */
134 private function addMethods( array $methods ): array {
135 $zoneId = $this->contextResolver->getShippingZoneId();
136 if ( $zoneId === null ) {
137 return $this->addAllMethods( $methods );
138 }
139
140 $allowedCountries = $this->shippingZoneRepository->getCountryCodesForShippingZone( $zoneId );
141 if ( $allowedCountries === [] ) {
142 return $this->addAllMethods( $methods );
143 }
144
145 foreach ( $allowedCountries as $countryCode ) {
146 $carriers = $this->carrierRepository->getByCountryIncludingNonFeed( $countryCode, false );
147 foreach ( $carriers as $carrier ) {
148 foreach ( $this->getGeneratedClassnames() as $fullyQualifiedClassname ) {
149 if ( $carrier->getId() === $fullyQualifiedClassname::CARRIER_ID ) {
150 $methods = $this->addActiveCarrierMethod( $fullyQualifiedClassname, $methods );
151
152 break;
153 }
154 }
155 }
156 }
157
158 return $methods;
159 }
160
161 /**
162 * Add shipping methods to array.
163 *
164 * @param array<string, string> $methods Array.
165 *
166 * @return array<string, string>
167 */
168 private function addAllMethods( array $methods ): array {
169 foreach ( $this->getGeneratedClassnames() as $fullyQualifiedClassname ) {
170 $methods = $this->addActiveCarrierMethod( $fullyQualifiedClassname, $methods );
171 }
172
173 return $methods;
174 }
175
176 /**
177 * Adds shipping method to array in case the carrier is active.
178 *
179 * @param string $fullyQualifiedClassname Fully qualified classname.
180 * @param array<string, string> $methods Methods.
181 *
182 * @return array<string, string>
183 */
184 private function addActiveCarrierMethod( string $fullyQualifiedClassname, array $methods ): array {
185 /**
186 * Generated shipping method.
187 *
188 * @var BaseShippingMethod $fullyQualifiedClassname
189 */
190 // @phpstan-ignore-next-line
191 $carrierOptions = $this->carrierOptionsFactory->createByCarrierId( $fullyQualifiedClassname::CARRIER_ID );
192 if ( $carrierOptions->isActive() ) {
193 $methods[ $fullyQualifiedClassname::getShippingMethodId() ] = $fullyQualifiedClassname;
194 }
195
196 return $methods;
197 }
198
199 /**
200 * Sort classnames by method_title property.
201 *
202 * @param array<string, string> $methods Methods to sort.
203 *
204 * @return array<string, string>
205 */
206 private function sortMethods( array $methods ): array {
207 uasort(
208 $methods,
209 function ( $classA, $classB ) {
210 $objectA = new $classA();
211 $objectB = new $classB();
212
213 // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
214 return strcmp( $objectA->method_title, $objectB->method_title );
215 }
216 );
217
218 return $methods;
219 }
220
221 /**
222 * @param array<string, string> $originalMethods
223 *
224 * @return array<string, string>
225 */
226 public function getSortedCachedMethods( array $originalMethods ): array {
227 $areClassesLoaded = in_array( BaseShippingMethod::class, get_declared_classes(), true );
228 if ( $areClassesLoaded === false ) {
229 return $originalMethods;
230 }
231
232 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
233 $cacheKey = crc32( serialize( $originalMethods ) );
234
235 if ( ! isset( self::$sortedMethodsCache[ $cacheKey ] ) ) {
236 $unsortedMethods = $this->addMethods( $originalMethods );
237 self::$sortedMethodsCache[ $cacheKey ] = $this->sortMethods( $unsortedMethods );
238 }
239
240 return self::$sortedMethodsCache[ $cacheKey ];
241 }
242 }
243