Skip to content

Instantly share code, notes, and snippets.

@Radiergummi
Last active September 16, 2017 07:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Radiergummi/3c402345f249a22b75a8afa240a1fba5 to your computer and use it in GitHub Desktop.
Save Radiergummi/3c402345f249a22b75a8afa240a1fba5 to your computer and use it in GitHub Desktop.
CraftCMS API Wrapper class
<?php
namespace Craft;
use Closure;
use function array_merge;
/**
* API endpoints wrapper
*
* @package config\api
*/
class Api {
/**
* current API version. will be false if there's no version.
*
* @var int|bool
*/
protected $version;
/**
* API URI prefix
*
* @var string
*/
protected $baseURI;
/**
* API endpoints
*
* @var array
*/
protected $endpoints = [];
/**
* holds the endpoint defaults
*
* @var array
*/
protected $defaults = [];
/**
* Api constructor
*
* @param string $baseURI API base URI prefix
* @param int|null $version Current API version. Omit to skip versioning.
*/
public function __construct( string $baseURI = 'api', int $version = null ) {
$this->baseURI = $baseURI;
$this->version = $version ?? false;
}
/**
* adds an endpoint to the API
*
* @param string $uri relative endpoint URI to add
* @param Closure $handler handler this endpoint will call
*
* @return void
*/
public function addEndpoint( string $uri, Closure $handler ) {
$this->endpoints[ $this->buildEndpointURI( $uri ) ] = $handler;
}
/**
* builds an endpoint URI
*
* @param string $uri relative URI to prepend the base URI prefix and version, if set
*
* @return string
*/
protected function buildEndpointURI( string $uri ): string {
$uri = ltrim($uri, '/');
if ( $this->version ) {
return "{$this->baseURI}/v{$this->version}/$uri";
}
return "{$this->baseURI}/$uri";
}
/**
* Adds a collection. This will call a callback with a new Api instance as its call context
* and merged with the existing endpoints later on.
* Collections can be nested, too.
*
* @param string $uri URI for all members of the group
* @param \Closure $endpointsCallback callback which makes changes to the collection
*
* @return void
*/
public function addCollection( string $uri, Closure $endpointsCallback ) {
// create a new Api instance with the given URI as its base URI
$collection = new self( $this->buildEndpointURI( $uri ) );
// call the endpoints callback with the collection passed as context.
// this means all methods need to be called on "$this" or use the arguments
$endpointsCallback->call( $collection, $collection, $this );
// merge the resulting endpoints
$this->endpoints = array_merge( $this->getEndpoints(), $collection->getEndpoints() );
}
/**
* retrieves the API endpoints
*
* @return array
*/
public function getEndpoints(): array {
return $this->endpoints;
}
/**
* removes an endpoint
*
* @param string $uri relative endpoint URI to remove. Will be run through buildEndpointURI
*
* @return void
*/
public function removeEndpoint( string $uri ) {
unset( $this->endpoints[ $this->buildEndpointURI( $uri ) ] );
}
/**
* retrieves the Api version
*
* @return int
*/
public function getVersion(): int {
return $this->version;
}
/**
* retrieves the API URI prefix
*
* @return string
*/
public function getBaseURI(): string {
return $this->baseURI;
}
/**
* converts the API definitions into an array consumable by the elementAPI plugin
*
* @return array
*/
public function toArray() {
return [
'defaults' => $this->getDefaults(),
'endpoints' => $this->getEndpoints()
];
}
/**
* retrieves the default endpoint settings
*
* @return array
*/
public function getDefaults(): array {
return $this->defaults;
}
/**
* sets the default endpoint settings
*
* @param array $defaults default settings to apply for this configuration. Will be ignored if set
* on a collection.
*/
public function setDefaults( array $defaults ) {
$this->defaults = $defaults;
}
}
<?php
namespace Craft;
$myApi = new Api('api', 1);
// endpoint for /api/v1/news
$myApi->addEndpoint( 'news.json', function() {
return [
'elementType' => Entry::class,
'criteria' => ['section' => 'news'],
'transformer' => function(Entry $entry) {
return [
'title' => $entry->title,
'url' => $entry->url,
'jsonUrl' => UrlHelper::url("news/{$entry->id}.json"),
'summary' => $entry->summary,
];
},
];
} );
// collection for /api/v1/receipts/
$myApi->addCollection( 'receipts', function( Api $collection, Api $api ) {
// endpoint for /api/v1/receipts/:id.json
$this->addEndpoint( '<entryId:\d+>.json', function() { /* ... */ } );
// collection for /api/v1/receipts/ingredients/
$this->addCollection( 'ingredients', function() {
// endpoint for /api/v1/receipts/ingredients/:id.json
$this->addEndpoint( '<entryId:\d+.json', function() { /* ... */ } );
} );
} );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment