PluginProbe
Packeta / 2.1
Packeta v2.1
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 2.1, at src/Packetery/Module/Shipping/ShippingProvider.php

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