digiaonline / lumen-contentful-sync
A framework for synchronizing content from Contentful to a Lumen API
Installs: 21 331
Dependents: 0
Suggesters: 0
Security: 0
Stars: 3
Watchers: 7
Forks: 2
Open Issues: 0
Requires
- php: >=7.1
- digiaonline/json-helpers: ^1.0
- jalle19/laravel-lost-interfaces: ^1.2
- laravel/lumen-framework: ^5.4|^6.0
- nordsoftware/lumen-contentful: ^4.2
- nordsoftware/lumen-newrelic: ^2.0
Requires (Dev)
- phpstan/phpstan: ^0.9.2
- phpunit/phpunit: ^6.5
README
Introduction
This library provides a powerful abstraction on top of digiaonline/lumen-contentful with the goal of making it easier to synchronize content from Contentful to your application.
Features
- console commands for synchronizing entries and assets
- a controller for handling webhooks
- a middleware for transparently authenticating webhook requests
- a middleware for proper New Relic transaction name instrumentation for webhook requests
- asynchronous processing support by using jobs
Requirements
- PHP >= 7.1
Installation
- Start by adding the library as a dependency to your application:
composer require digiaonline/lumen-contentful-sync
- Copy
config/contentfulSync.php
to your configuration directory. There is only one mandatory configuration key -content_types
. This array should contain a list of all the content model IDs you have in your Contentful space, e.g.:
<?php return [ 'content_types' => [ 'article', 'person', 'video', ], // ... ];
-
Extend
Digia\Lumen\ContentfulSync\Services\AbstractContentfulSyncService
and implement the necessary methods. This is where the logic for how to handle entries and assets will live. See the next section for more details. -
Extend
Digia\Lumen\ContentfulSync\Providers\AbstractContentfulSyncServiceProvider
and implement theregisterContentfulSyncServiceBindings
method. A typical implementation would look like this:
protected function registerContentfulSyncServiceBindings(Application $app) { // ContentfulSyncService is the concrete implementation we made in step 3 $app->singleton(ContentfulSyncServiceContract::class, function (Application $app) { return new ContentfulSyncService($app->make(Queue::class)); }); }
- Register the service provider you just implemented:
$app->register(\Your\ServiceProvider::class);
- Register the console commands in your kernel:
protected $commands = [ // ... SyncAssetsCommand::class, SyncContentsCommand::class, ];
- If you intend to use webhooks you will have to configure a route to the controller. In this example we will use both the New Relic and the webhook authentication middlewares, but both are optional:
// The route URL is arbitrary, just make sure it matches what you have configured in Contentful $app->post('/contentful/handleIncomingWebhook', [ 'middleware' => [ \Digia\Lumen\ContentfulSync\Http\Middleware\WebhookAuthenticationMiddleware::class, \Digia\Lumen\ContentfulSync\Http\Middleware\NewRelicMiddleware::class, ], 'uses' => 'Digia\Lumen\ContentfulSync\Http\Controllers\ContentfulSyncController@handleIncomingWebhook', ]);
- If you use the webhook authentication middleware you can configure the username and password to expect by adding
these to your
.env
file:
CONTENTFUL_SYNC_WEBHOOK_USERNAME=username
CONTENTFUL_SYNC_WEBHOOK_PASSWORD=password
If you need more complicated logic you will have to create your own middleware.
Implementing the service
Since all applications are different it is up to you to define how to handle your entries and assets.
The unimplemented methods give you the asset/entry in question as JSON. You will most likely want to use the SDK to convert these blobs to actual objects:
/** * @inheritdoc */ public function handleEntryPublished(string $contentType, string $entryJson, bool $ignoreExisting): void { // We're assuming here that you have injected an instance of ContentfulServiceContract $entry = $this->contentfulService->getClient()->reviveJson($entryJson); // You can now do e.g. $entry->getTitle(); etc. depending on your content model }
Usage
Console commands
To synchronize all assets and all configured content types, run the following two commands:
php artisan contentful:assets:sync php artisan contentful:contents:sync
To synchronize all entries for a specific content type (article
in this case), run:
php artisan contentful:contents:sync article
To synchronize new entries only, run:
php artisan contentful:contents:sync article --ignoreExisting
You can add -v
or -vv
or -vvv
to both commands to get more detailed output and a progress bar, e.g.:
$ php artisan contentful:contents:sync article --ignoreExisting -vvv Synchronizing content of type "article"... 300/300 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% 3 secs/3 secs 32.0 MiB Done, synchronized 300 entries
New Relic middleware
If you use New Relic to monitor your application you will probably notice that all Contentful webhooks are lumped together as a single transacation (since they all use the same URL/route).
However, if you apply the
Digia\Lumen\ContentfulSync\Http\Middleware\NewRelicMiddleware
middleware to your route, transactions will be named
topic@contentType
, e.g. ContentManagement.Entry.publish@article
. This allows you to single in on particularly slow
webhooks.
Asynchronous processing
In your service provider implementation you can specify an instance of Illuminate\Contracts\Queue\Queue
to inject
into the service. Unless you've configured a different queue specifically your application will be using the
SyncQueue
implementation to simulate a completely synchronous queue.
By specifying a different queue instance you can offload all the work the service does to queue workers.
License
MIT