laulamanapps / apple-passbook-bundle
Generate Apple Passbooks from your Symfony application
Installs: 18 493
Dependents: 0
Suggesters: 1
Security: 0
Stars: 3
Watchers: 2
Forks: 2
Open Issues: 2
Requires
- php: >=7.3
- ext-openssl: *
- laulamanapps/apple-passbook: ^1.1
Requires (Dev)
- ext-zip: *
- matthiasnoback/symfony-config-test: ^4.1
- symfony/browser-kit: ^5.1
- symfony/event-dispatcher: ^5.1
- symfony/framework-bundle: ^5.1
- symfony/http-foundation: ^5.1
- symfony/routing: ^5.1
- symfony/yaml: ^5.1
Suggests
- symfony/event-dispatcher: ^5.1
- symfony/framework-bundle: ^5.1
- symfony/http-foundation: ^5.1
- symfony/routing: ^5.1
This package is auto-updated.
Last update: 2024-11-10 03:27:55 UTC
README
This package provides Symfony configuration for LauLamanApps Apple Passbook Package
Installation
With composer, add:
$ composer require laulamanapps/apple-passbook-bundle
Run Tests
To make sure everything works you can run tests:
$ make tests-unit $ make tests-integration $ make tests-infection
Get certificate
Head over to the Apple Developer Portal to get yourself a certificate to sign your passbooks with.
Convert the certificate and key to a .p12 file using the Keychain Access
Configure Bundle
#config/packages/laulamanapps_apple_passbook.yml laulamanapps_apple_passbook: certificate: '%env(APPLE_PASSBOOK_CERTIFICATE)%' password: '%env(APPLE_PASSBOOK_CERTIFICATE_PASSWORD)%' team_identifier: '%env(APPLE_PASSBOOK_TEAM_IDENTIFIER)%' pass_type_identifier: '%env(APPLE_PASSBOOK_PASS_TYPE_IDENTIFIER)%'
Add the ENV variables to the .env
file
##> laulamanapps/apple-passbook-bundle APPLE_PASSBOOK_CERTIFICATE=path/to/certificate.p12 APPLE_PASSBOOK_CERTIFICATE_PASSWORD=password APPLE_PASSBOOK_PASS_TYPE_IDENTIFIER=pass.com.your.pass.identifiers APPLE_PASSBOOK_TEAM_IDENTIFIER=identifier APPLE_PASSBOOK_WEB_SERVICE_URL='http://example.com/' ##< laulamanapps/apple-passbook-bundle
Create & Compile Passbook
namespace App\Controller; use LauLamanApps\ApplePassbook\Build\Compiler; use LauLamanApps\ApplePassbook\GenericPassbook; use LauLamanApps\ApplePassbook\MetaData\Barcode; use LauLamanApps\ApplePassbook\Style\BarcodeFormat; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Annotation\Route; final class PassbookController extends AbstractController { /** * @var Compiler */ private $passbookCompiler; public function __construct(Compiler $passbookCompiler) { $this->passbookCompiler = $passbookCompiler; } /** * @Route("/download/passbook/", name="download_passbook") */ public function download(): Response { $passbook = new GenericPassbook('8j23fm3'); $passbook->setTeamIdentifier('<TeamId>'); $passbook->setPassTypeIdentifier('<PassTypeId>'); $passbook->setOrganizationName('Toy Town'); $passbook->setDescription('Toy Town Membership'); $barcode = new Barcode(); $barcode->setFormat(BarcodeFormat::pdf417()); $barcode->setMessage('123456789'); $passbook->setBarcode($barcode); $data = $this->passbookCompiler->compile($passbook); $response = new Response($data); $response->headers->set('Content-Description', 'File Transfer'); $response->headers->set('Content-Type', 'application/vnd.apple.pkpass'); $response->headers->set('Content-Disposition', 'filename="passbook.pkpass"'); return $response; } }
Configure Build in Webservices
This package comes with build in controllers for all Apple passbooks webservice URLs.
It is using Symfonys build in EventDispatcher
.
Enable this by adding the following configuration to the config/routes/routes.yaml
passbook_routes: resource: '@ApplePassbookBundle/Controller/' type: annotation
The controllers will dispatch the following events, the following information is available:
/* Available on All events */ $event->getPassTypeIdentifier(); $event->getStatus(); /* Available on DeviceRegisteredEvent */ $event->getAuthenticationToken(); $event->getDeviceLibraryIdentifier(); $event->getSerialNumber(); /* Available on DeviceRequestUpdatedPassesEvent */ $event->getAuthenticationToken(); $event->getDeviceLibraryIdentifier(); $event->getPassesUpdatedSince(); /* Available on DeviceUnregisteredEvent */ $event->getAuthenticationToken(); $event->getDeviceLibraryIdentifier(); $event->getSerialNumber(); /* Available on RetrieveUpdatedPassbookEvent */ $event->getAuthenticationToken(); $event->getSerialNumber(); $event->getPassTypeIdentifier(); $event->getUpdatedSince();
Now Subscribe to the events:
The idea here is that you handle the event and mark the events as handled by calling setters on the event itself.
The event by default has the status Status::unhandled()
namespace App\Integration\Symfony\EventSubscriber; use DateTimeImmutable; use LauLamanApps\ApplePassbook\GenericPassbook; use LauLamanApps\ApplePassbookBundle\Event\DeviceRegisteredEvent; use LauLamanApps\ApplePassbookBundle\Event\DeviceRequestUpdatedPassesEvent; use LauLamanApps\ApplePassbookBundle\Event\DeviceUnregisteredEvent; use LauLamanApps\ApplePassbookBundle\Event\RetrieveUpdatedPassbookEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; final class ApplePassbookSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ DeviceRegisteredEvent::class => 'onDeviceRegistered', DeviceRequestUpdatedPassesEvent::class => 'onDeviceRequestUpdatedPasses', RetrieveUpdatedPassbookEvent::class => 'onRetrieveUpdatedPassbook', DeviceUnregisteredEvent::class => 'onDeviceUnregistered', ]; } public function onDeviceRegistered(DeviceRegisteredEvent $event): void { $passbook = $this->passbookRepository->getBySerial($event->getSerialNumber()); if ($event->getAuthenticationToken() <> $passbook->getAuthToken()) { $event->notAuthorized(); return; } /** * Save in Database */ $event->deviceRegistered(); } public function onDeviceRequestUpdatedPasses(DeviceRequestUpdatedPassesEvent $event): void { $passbooks = $this->passbookRepository->getSerialsSince( $event->getPassTypeIdentifier(), $event->getDeviceLibraryIdentifier(), $event->getPassesUpdatedSince() ); if ($passbooks) { $serials = []; foreach ($passbooks as $passbook) { $serials[] = $passbook->getSerialNumber(); } $event->setSerialNumbers($serials, new DateTimeImmutable()); return; } $event->notFound(); } public function onRetrieveUpdatedPassbook(RetrieveUpdatedPassbookEvent $event): void { try { $entity = $this->passbookRepository->getBySerial($event->getSerialNumber()); if ($entity->getAuthToken() !== $event->getAuthenticationToken()) { $event->notAuthorized(); return; } if ($event->getUpdatedSince() && $entity->getUpdatedAt() < $event->getUpdatedSince()) { $event->notModified(); return; } $passbook = new GenericPassbook($event->getSerialNumber()); /* Generate Passbook */ $event->setPassbook($passbook); } catch (NoResultException $e) { $event->notFound(); } } public function onDeviceUnregistered(DeviceUnregisteredEvent $event): void { $passbook = $this->passbookRepository->getBySerial($event->getSerialNumber()); if ($event->getAuthenticationToken() <> $passbook->getAuthToken()) { $event->notAuthorized(); return; } /** * Remove from Database */ $event->deviceUnregistered(); } }
Credits
This package has been developed by LauLaman.