PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.18
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.18
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
← All changes | includes/Services/Provider.php +191 -2 1.9.161.10.18 View file →
@@ -1,10 +1,11 @@
1 1 <?php
2 2 /**
3 3 * Cloud-print provider capabilities value object.
4 4 *
5 - * Single source of truth for per-provider knowledge: validity, polling,
6 - * content types, poll endpoints, server diagnostics and thermal wire formats.
5 + * Single source of truth for per-provider knowledge: validity, the default for
6 + * rows without a provider, polling, content types, poll endpoints, server
7 + * diagnostics, thermal wire formats and renderable template engines.
7 8 *
8 9 * @package WCPOS\WooCommercePOS\Services
9 10 */
10 11
@@ -9,13 +10,28 @@
9 10 */
10 11
11 12 namespace WCPOS\WooCommercePOS\Services;
12 13
14 +use WCPOS\WooCommercePOS\Interfaces\Provider_Adapter_Interface;
15 +use WCPOS\WooCommercePOS\Interfaces\Poll_Provider_Adapter_Interface;
16 +use WCPOS\WooCommercePOS\Services\Providers\Epson_Sdp_Adapter;
17 +use WCPOS\WooCommercePOS\Services\Providers\Printnode_Adapter;
18 +use WCPOS\WooCommercePOS\Services\Providers\Star_Cloudprnt_Adapter;
19 +use WCPOS\WooCommercePOS\Services\Providers\Star_Online_Adapter;
20 +
13 21 /**
14 22 * Provider class.
15 23 */
16 24 class Provider {
17 25 /**
26 + * Provider assumed for printer rows that predate the provider field.
27 + *
28 + * Star CloudPRNT was the only provider before the field existed, so a row
29 + * without one is a Star CloudPRNT printer.
30 + */
31 + public const DEFAULT_PROVIDER = 'star-cloudprnt';
32 +
33 + /**
18 34 * Per-provider capability map.
19 35 *
20 36 * @var array<string, array<string, mixed>>
21 37 */
@@ -28,8 +44,14 @@
28 44 'content_type' => 'application/vnd.star.starprnt',
29 45 'poll_endpoint' => 'cloudprnt',
30 46 'supports_server_diagnostic' => true,
31 47 'thermal_wire_format' => 'starprnt',
48 + 'template_engines' => 'thermal',
49 + 'stores_job_kind' => false,
50 + // The StarPRNT emitter emits a native drawer pulse (and inserts one
51 + // before the trailing cut when a job asks for it), so drawer metadata
52 + // has to survive to render time.
53 + 'supports_drawer' => true,
32 54 ),
33 55 'epson-sdp' => array(
34 56 'polling' => true,
35 57 'content_type' => 'application/xml',
@@ -35,8 +57,11 @@
35 57 'content_type' => 'application/xml',
36 58 'poll_endpoint' => 'epson-sdp',
37 59 'supports_server_diagnostic' => true,
38 60 'thermal_wire_format' => 'epos-xml',
61 + 'template_engines' => 'thermal',
62 + 'stores_job_kind' => false,
63 + 'supports_drawer' => true,
39 64 ),
40 65 'printnode' => array(
41 66 'polling' => false,
42 67 'content_type' => 'application/pdf',
@@ -42,8 +67,11 @@
42 67 'content_type' => 'application/pdf',
43 68 'poll_endpoint' => null,
44 69 'supports_server_diagnostic' => false,
45 70 'thermal_wire_format' => null,
71 + 'template_engines' => 'all',
72 + 'stores_job_kind' => true,
73 + 'supports_drawer' => true,
46 74 ),
47 75 'star-online' => array(
48 76 'polling' => false,
49 77 'content_type' => 'text/vnd.star.markup',
@@ -49,8 +77,11 @@
49 77 'content_type' => 'text/vnd.star.markup',
50 78 'poll_endpoint' => null,
51 79 'supports_server_diagnostic' => false,
52 80 'thermal_wire_format' => 'star-markup',
81 + 'template_engines' => 'thermal',
82 + 'stores_job_kind' => false,
83 + 'supports_drawer' => false,
53 84 ),
54 85 );
55 86
56 87 /**
@@ -62,8 +93,106 @@
62 93 return array_keys( self::CAPABILITIES );
63 94 }
64 95
65 96 /**
97 + * Resolve a stored printer row's provider to a known provider key.
98 + *
99 + * Callers read `$printer['provider']` from an option that predates the
100 + * field, so the value can be missing, empty, or (for hand-edited options)
101 + * a key this build does not know. All three resolve to the default rather
102 + * than to a silent no-provider state.
103 + *
104 + * @param string|null $provider Raw provider value from a printer row.
105 + *
106 + * @return string A key from self::valid().
107 + */
108 + public static function normalize( ?string $provider ): string {
109 + return \in_array( $provider, self::valid(), true ) ? (string) $provider : self::DEFAULT_PROVIDER;
110 + }
111 +
112 + /**
113 + * Resolve a provider adapter.
114 + *
115 + * An empty legacy-row value uses normalize()'s Star CloudPRNT default;
116 + * non-empty unknown keys remain unknown and return null.
117 + *
118 + * @param string $provider Provider key or empty legacy-row value.
119 + *
120 + * @return Provider_Adapter_Interface|null
121 + */
122 + public static function adapter( string $provider ): ?Provider_Adapter_Interface {
123 + $provider = '' === $provider ? self::normalize( $provider ) : $provider;
124 +
125 + switch ( $provider ) {
126 + case 'star-cloudprnt':
127 + return new Star_Cloudprnt_Adapter();
128 + case 'epson-sdp':
129 + return new Epson_Sdp_Adapter();
130 + case 'printnode':
131 + return new Printnode_Adapter();
132 + case 'star-online':
133 + return new Star_Online_Adapter();
134 + default:
135 + return null;
136 + }
137 + }
138 +
139 + /**
140 + * Resolve the wire format and HTTP content type for a print job.
141 + *
142 + * @param array $printer Printer configuration.
143 + * @param array $template Template configuration.
144 + *
145 + * @return array{kind:string, content_type:string}
146 + */
147 + public static function format( array $printer, array $template ): array {
148 + // Printer rows saved before the provider field existed have none; they must behave as the default provider.
149 + $provider = self::normalize( \is_string( $printer['provider'] ?? null ) ? $printer['provider'] : null );
150 + $adapter = self::adapter( $provider );
151 + if ( null === $adapter ) {
152 + return array(
153 + 'kind' => '',
154 + 'content_type' => '',
155 + );
156 + }
157 +
158 + return $adapter->format( $printer, $template );
159 + }
160 +
161 + /**
162 + * Resolve the HTTP content type for a printer when no template is in hand.
163 + *
164 + * The reprint path uses this only when the template cannot be rendered and
165 + * the job carries no `pn_kind`; otherwise it keeps the stored content type
166 + * so the two halves cannot drift apart.
167 + *
168 + * PrintNode reports its PDF default even for a printer in raw mode. The
169 + * reprint path's `pn_kind` condition keeps raw jobs away from this answer.
170 + * Prefer format() when a template is in hand to resolve both halves together.
171 + *
172 + * @param array $printer Printer configuration.
173 + *
174 + * @return string
175 + */
176 + public static function printer_content_type( array $printer ): string {
177 + $provider = self::normalize( \is_string( $printer['provider'] ?? null ) ? $printer['provider'] : null );
178 + $adapter = self::adapter( $provider );
179 +
180 + return null === $adapter ? 'application/octet-stream' : $adapter->content_type();
181 + }
182 +
183 + /**
184 + * Resolve only polling adapters without widening the base provider contract.
185 + *
186 + * @param string $key Provider key.
187 + * @return Poll_Provider_Adapter_Interface|null
188 + */
189 + public static function poll_adapter( string $key ): ?Poll_Provider_Adapter_Interface {
190 + $adapter = self::adapter( $key );
191 + return $adapter instanceof Poll_Provider_Adapter_Interface ? $adapter : null;
192 + }
193 +
194 + /**
66 195 * Whether the provider polls the server for jobs.
67 196 *
68 197 * @param string $provider Provider key.
69 198 *
@@ -134,6 +263,66 @@
134 263 return null;
135 264 }
136 265
137 266 return self::CAPABILITIES[ $provider ]['thermal_wire_format'] ?? null;
267 + }
268 +
269 + /**
270 + * Receipt-template engines the provider can render for automatic jobs.
271 + *
272 + * 'all' means every active template; 'thermal' means thermal templates
273 + * only. Unknown providers are treated as thermal-only, the conservative
274 + * answer for a printer we cannot render a PDF for.
275 + *
276 + * @param string $provider Provider key.
277 + *
278 + * @return string 'all' or 'thermal'.
279 + */
280 + public static function template_engines( string $provider ): string {
281 + return (string) ( self::CAPABILITIES[ $provider ]['template_engines'] ?? 'thermal' );
282 + }
283 +
284 + /**
285 + * Whether jobs for the provider persist their resolved kind separately.
286 + *
287 + * @param string $provider Provider key.
288 + *
289 + * @return bool
290 + */
291 + public static function stores_job_kind( string $provider ): bool {
292 + return (bool) ( self::CAPABILITIES[ $provider ]['stores_job_kind'] ?? false );
293 + }
294 +
295 + /**
296 + * Whether the provider supports the generic drawer metadata contract.
297 + *
298 + * @param string $provider Provider key.
299 + *
300 + * @return bool
301 + */
302 + public static function supports_drawer( string $provider ): bool {
303 + return (bool) ( self::CAPABILITIES[ $provider ]['supports_drawer'] ?? false );
304 + }
305 +
306 + /**
307 + * Per-provider facts the settings screen cannot derive, keyed by provider.
308 + *
309 + * Projected onto the cloud-print settings response (cf.
310 + * Cloud_Print_Relay_Service::public_state()) so the admin app can read the
311 + * provider table from the server instead of re-declaring it. Deliberately
312 + * narrow: presentation (labels, badges) stays in the client, and facts the
313 + * client already renders from its own table are not duplicated here until
314 + * something reads them.
315 + *
316 + * @return array<string, array<string, string>>
317 + */
318 + public static function public_capabilities(): array {
319 + $capabilities = array();
320 + foreach ( self::valid() as $provider ) {
321 + $capabilities[ $provider ] = array(
322 + 'template_engines' => self::template_engines( $provider ),
323 + );
324 + }
325 +
326 + return $capabilities;
138 327 }
139 328 }