Appointments
2 weeks ago
Events
2 weeks ago
GetMobileInfoController.php
2 weeks ago
MobileV1Controller.php
2 weeks ago
GetMobileInfoController.php
106 lines
| 1 | <?php |
| 2 | |
| 3 | namespace AmeliaBooking\Application\Controller\Mobile; |
| 4 | |
| 5 | use AmeliaBooking\Application\Controller\Controller; |
| 6 | use AmeliaBooking\Infrastructure\Licence\Licence; |
| 7 | use AmeliaVendor\Psr\Http\Message\ServerRequestInterface as Request; |
| 8 | use AmeliaVendor\Psr\Http\Message\ResponseInterface as Response; |
| 9 | |
| 10 | /** |
| 11 | * Version-negotiation handshake for the Amelia Staff mobile app. |
| 12 | * |
| 13 | * The mobile app talks to the versioned /mobile/v1/* routes, but different sites |
| 14 | * run different plugin builds. This endpoint lets the app detect version skew |
| 15 | * BEFORE it makes (or fails) a real call, so it can show a precise "update the |
| 16 | * plugin" vs "update the app" dialog instead of a cryptic 404. |
| 17 | * |
| 18 | * Contract (must stay stable FOREVER — it is the thing used to detect breaking |
| 19 | * changes, so it can never itself have one): |
| 20 | * |
| 21 | * GET /mobile/info -> 200 { |
| 22 | * "message": "success", |
| 23 | * "data": { |
| 24 | * "pluginVersion": "9.5", // AMELIA_VERSION, informational |
| 25 | * "mobileApi": { "min": 1, "max": 1}, // inclusive range of mobile-API |
| 26 | * // contract versions this build serves |
| 27 | * "licenseOk": true // false when the installed license does |
| 28 | * // not include the mobile-app feature (Pro+) |
| 29 | * } |
| 30 | * } |
| 31 | * |
| 32 | * Deliberately: |
| 33 | * - UNVERSIONED — lives outside /mobile/v1/ so it survives any contract change. |
| 34 | * - UNAUTHENTICATED — extends the base Controller (NOT MobileV1Controller, which |
| 35 | * forces a Bearer token) and returns its payload directly, bypassing the |
| 36 | * command/handler pipeline. No token, nonce, API key or DB access. The app |
| 37 | * calls it before login, so it must work with no credentials. |
| 38 | * |
| 39 | * The app declares the single contract version it was built against and compares: |
| 40 | * appVersion > max -> plugin too old -> "update the plugin" |
| 41 | * appVersion < min -> contract dropped -> "update the app" (force-update case) |
| 42 | * otherwise -> compatible |
| 43 | * |
| 44 | * Release invariant: this endpoint MUST ship in the same release as the |
| 45 | * /mobile/v1/* routes (see MobileV1.php), otherwise the very release that |
| 46 | * introduces mobile support would fail its own compatibility check. |
| 47 | * |
| 48 | * Bump protocol for the constants below: |
| 49 | * - Raise MOBILE_API_MAX when adding a new, additive mobile-API contract version. |
| 50 | * - Raise MOBILE_API_MIN only when DELIBERATELY dropping support for an older app |
| 51 | * contract — this forces those app builds to update. |
| 52 | */ |
| 53 | class GetMobileInfoController extends Controller |
| 54 | { |
| 55 | /** Oldest mobile-API contract version this plugin build still serves. */ |
| 56 | public const MOBILE_API_MIN = 1; |
| 57 | |
| 58 | /** Newest mobile-API contract version this plugin build serves. */ |
| 59 | public const MOBILE_API_MAX = 1; |
| 60 | |
| 61 | /** |
| 62 | * @param Request $request |
| 63 | * @param Response $response |
| 64 | * @param $args |
| 65 | * @param bool $validApiCall |
| 66 | * |
| 67 | * @return Response |
| 68 | */ |
| 69 | public function __invoke(Request $request, Response $response, $args, $validApiCall = false) |
| 70 | { |
| 71 | $response = $response->withStatus(self::STATUS_OK); |
| 72 | $response = $response->withHeader('Content-Type', 'application/json;charset=utf-8'); |
| 73 | $response->getBody()->write( |
| 74 | json_encode( |
| 75 | [ |
| 76 | 'message' => 'success', |
| 77 | 'data' => [ |
| 78 | 'pluginVersion' => defined('AMELIA_VERSION') ? AMELIA_VERSION : null, |
| 79 | 'mobileApi' => [ |
| 80 | 'min' => self::MOBILE_API_MIN, |
| 81 | 'max' => self::MOBILE_API_MAX, |
| 82 | ], |
| 83 | 'licenseOk' => Licence::hasFeatureAccess('mobileApp'), |
| 84 | ], |
| 85 | ] |
| 86 | ) |
| 87 | ); |
| 88 | |
| 89 | return $response; |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Required by the base Controller, but never reached: __invoke returns the |
| 94 | * static handshake payload directly and never enters the command pipeline. |
| 95 | * |
| 96 | * @param Request $request |
| 97 | * @param $args |
| 98 | * |
| 99 | * @return null |
| 100 | */ |
| 101 | protected function instantiateCommand(Request $request, $args) |
| 102 | { |
| 103 | return null; |
| 104 | } |
| 105 | } |
| 106 |