Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Airtable Integration: Extract AirtableDatasource & leverage it for built-in & dynamic datasources #17

Merged
merged 11 commits into from
Sep 13, 2024
Original file line number Diff line number Diff line change
@@ -39,6 +39,6 @@ class AirtableEldenRingListLocationsQuery extends QueryContext {
];

public function get_endpoint( array $input_variables ): string {
return $this->get_datasource()->get_endpoint() . '/' . AirtableEldenRingMapDatasource::LOCATIONS_TABLE . '?filterByFormula=FIND%28%27' . $input_variables['map_name'] . '%27%2C%20%7BMap%7D%29%3E0';
return $this->get_datasource()->get_endpoint( 'locations' ) . '?filterByFormula=FIND%28%27' . $input_variables['map_name'] . '%27%2C%20%7BMap%7D%29%3E0';
}
}
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ class AirtableEldenRingListMapsQuery extends QueryContext {
];

public function get_endpoint( $input_variables ): string {
return $this->get_datasource()->get_endpoint() . '/' . AirtableEldenRingMapDatasource::MAPS_TABLE;
return $this->get_datasource()->get_endpoint( 'maps' );
}

public function get_query_name(): string {

This file was deleted.

9 changes: 7 additions & 2 deletions example/airtable/elden-ring-map/register.php
Original file line number Diff line number Diff line change
@@ -2,27 +2,32 @@

namespace RemoteDataBlocks\Example\Airtable\EldenRingMap;

use RemoteDataBlocks\Config\AirtableDatasource;
use RemoteDataBlocks\Editor\ConfigurationLoader;
use RemoteDataBlocks\Logging\LoggerManager;
use function register_block_type;
use function wp_register_script;
use function wp_register_style;

require_once __DIR__ . '/inc/queries/class-airtable-elden-ring-map-datasource.php';
require_once __DIR__ . '/inc/queries/class-airtable-elden-ring-list-locations-query.php';
require_once __DIR__ . '/inc/queries/class-airtable-elden-ring-list-maps-query.php';

function register_airtable_elden_ring_map_block() {
$block_name = 'Elden Ring Location';
$access_token = \RemoteDataBlocks\Example\get_access_token( 'airtable_elden_ring' );
$base = 'appqI3sJ9R2NcML8Y';
$tables = [
'maps' => 'tblS3OYo8tZOg04CP',
'locations' => 'tblc82R9msH4Yh6ZX',
];

if ( empty( $access_token ) ) {
$logger = LoggerManager::instance();
$logger->warning( sprintf( '%s is not defined, cannot register %s block', 'EXAMPLE_AIRTABLE_ELDEN_RING_ACCESS_TOKEN', $block_name ) );
return;
}

$elden_ring_datasource = new AirtableEldenRingMapDatasource( $access_token );
$elden_ring_datasource = new AirtableDatasource( $access_token, $base, $tables );
$list_locations_query = new AirtableEldenRingListLocationsQuery( $elden_ring_datasource );
$list_maps_query = new AirtableEldenRingListMapsQuery( $elden_ring_datasource );

This file was deleted.

6 changes: 4 additions & 2 deletions example/airtable/events/register.php
Original file line number Diff line number Diff line change
@@ -2,25 +2,27 @@

namespace RemoteDataBlocks\Example\Airtable\Events;

use RemoteDataBlocks\Config\AirtableDatasource;
use RemoteDataBlocks\Editor\ConfigurationLoader;
use RemoteDataBlocks\Logging\LoggerManager;
use function add_action;

require_once __DIR__ . '/inc/queries/class-airtable-events-datasource.php';
require_once __DIR__ . '/inc/queries/class-airtable-get-event-query.php';
require_once __DIR__ . '/inc/queries/class-airtable-list-events-query.php';

function register_airtable_events_block() {
$block_name = 'Airtable Event';
$access_token = \RemoteDataBlocks\Example\get_access_token( 'airtable_events' );
$base = 'appVQ2PAl95wQSo9S';
$table = 'tblyGtuxblLtmoqMI';

if ( empty( $access_token ) ) {
$logger = LoggerManager::instance();
$logger->warning( sprintf( '%s is not defined, cannot register %s block', 'EXAMPLE_AIRTABLE_EVENTS_ACCESS_TOKEN', $block_name ) );
return;
}

$airtable_datasource = new AirtableEventsDatasource( $access_token );
$airtable_datasource = new AirtableDatasource( $access_token, $base, $table );
$airtable_get_event_query = new AirtableGetEventQuery( $airtable_datasource );
$airtable_list_events_query = new AirtableListEventsQuery( $airtable_datasource );

9 changes: 5 additions & 4 deletions example/shopify/register.php
Original file line number Diff line number Diff line change
@@ -2,29 +2,30 @@

namespace RemoteDataBlocks\Example\Shopify;

use RemoteDataBlocks\Config\ShopifyDatasource;
use RemoteDataBlocks\Config\ShopifyGetProductQuery;
use RemoteDataBlocks\Config\ShopifySearchProductsQuery;
use RemoteDataBlocks\Editor\ConfigurationLoader;
use RemoteDataBlocks\Logging\LoggerManager;
use function add_action;

require_once __DIR__ . '/inc/interactivity-store/interactivity-store.php';
require_once __DIR__ . '/inc/queries/class-shopify-datasource.php';
require_once __DIR__ . '/inc/queries/class-shopify-add-to-cart-mutation.php';
require_once __DIR__ . '/inc/queries/class-shopify-create-cart-mutation.php';
require_once __DIR__ . '/inc/queries/class-shopify-get-product-query.php';
require_once __DIR__ . '/inc/queries/class-shopify-remove-from-cart-mutation.php';
require_once __DIR__ . '/inc/queries/class-shopify-search-products-query.php';

function register_shopify_block() {
$block_name = 'Shopify Product';
$access_token = \RemoteDataBlocks\Example\get_access_token( 'shopify' );
$store_name = 'stoph-test';

if ( empty( $access_token ) ) {
$logger = LoggerManager::instance();
$logger->warning( sprintf( '%s is not defined, cannot register %s block', 'EXAMPLE_SHOPIFY_ACCESS_TOKEN', $block_name ) );
return;
}

$shopify_datasource = new ShopifyDatasource( $access_token );
$shopify_datasource = new ShopifyDatasource( $access_token, $store_name );
$shopify_search_products_query = new ShopifySearchProductsQuery( $shopify_datasource );
$shopify_get_product_query = new ShopifyGetProductQuery( $shopify_datasource );

46 changes: 46 additions & 0 deletions inc/config/airtable-datasource/airtable-datasource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace RemoteDataBlocks\Config;

use RemoteDataBlocks\Config\HttpDatasource;

class AirtableDatasource extends HttpDatasource {
use DynamicDatasource;

private $tables;

public function __construct( private string $access_token, private string $base, mixed $tables ) {
if ( ! is_array( $tables ) ) {
$tables = [ '' => $tables ];
}
$this->tables = $tables;
}

public function get_access_token(): string {
return $this->access_token;
}

public function get_base(): string {
return $this->base;
}

public function get_table( string $variation = '' ): string {
return $this->tables[ $variation ] ?? '';
}

public function get_endpoint( string $variation = '' ): string {
$url = 'https://api.airtable.com/v0/' . $this->get_base();
$table = $this->get_table( $variation );
if ( $table ) {
$url .= '/' . $table;
}
return $url;
}

public function get_request_headers(): array {
return [
'Authorization' => sprintf( 'Bearer %s', $this->get_access_token() ),
'Content-Type' => 'application/json',
];
}
}
24 changes: 24 additions & 0 deletions inc/config/dynamic-datasource-trait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace RemoteDataBlocks\Config;

trait DynamicDatasource {
private string $slug;
private string $uuid;

public function set_slug( string $slug ): void {
$this->slug = $slug;
}

public function get_slug(): string {
return $this->slug;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of the slug?

cc @shekharnwagh

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was meant to be the predictable unique identifier, so that we can reference the credentials in example code using this, and then users could tag the data source in the Settings Page with this slug. So the slug would act as a link between those 2 systems. Earlier we had uuid as unique identifier, but that is not predictable until user adds the data source from Setting Page. Open to other ideas if they seem easier, this was just the first thought that popped into my mind.


public function set_uuid( string $uuid ): void {
$this->uuid = $uuid;
}

public function get_uuid(): string {
return $this->uuid;
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
<?php

namespace RemoteDataBlocks\Example\Shopify;
namespace RemoteDataBlocks\Config;

use RemoteDataBlocks\Config\HttpDatasource;
use function plugins_url;

class ShopifyDatasource extends HttpDatasource {
public function __construct( private string $access_token ) {}
use DynamicDatasource;

public function __construct( private string $access_token, private string $store_name ) {}

public function get_store_name(): string {
return $this->store_name;
}

public function get_endpoint(): string {
return 'https://stoph-test.myshopify.com/api/2024-04/graphql.json';
return 'https://' . $this->store_name . '.myshopify.com/api/2024-04/graphql.json';
}

public function get_request_headers(): array {
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php

namespace RemoteDataBlocks\Example\Shopify;

use RemoteDataBlocks\Config\GraphqlQueryContext;
namespace RemoteDataBlocks\Config;

class ShopifyGetProductQuery extends GraphqlQueryContext {
public array $input_variables = [
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php

namespace RemoteDataBlocks\Example\Shopify;

use RemoteDataBlocks\Config\GraphqlQueryContext;
namespace RemoteDataBlocks\Config;

class ShopifySearchProductsQuery extends GraphqlQueryContext {
public array $input_variables = [
5 changes: 5 additions & 0 deletions inc/config/shopify-datasource/shopify-datasource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

require_once __DIR__ . '/class-shopify-datasource.php';
require_once __DIR__ . '/class-shopify-get-product-query.php';
require_once __DIR__ . '/class-shopify-search-products-query.php';
35 changes: 35 additions & 0 deletions inc/editor/configuration-loader/configuration-loader.php
Original file line number Diff line number Diff line change
@@ -6,8 +6,12 @@

use Error;
use RemoteDataBlocks\Config\QueryContext;
use RemoteDataBlocks\Config\ShopifyDatasource;
use RemoteDataBlocks\Config\ShopifyGetProductQuery;
use RemoteDataBlocks\Config\ShopifySearchProductsQuery;
use RemoteDataBlocks\Logging\Logger;
use RemoteDataBlocks\Logging\LoggerManager;
use RemoteDataBlocks\REST\DatasourceCRUD;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class should probably get moved out of the REST namespace

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.


use function add_action;
use function do_action;
@@ -28,6 +32,8 @@ public static function init() {
public static function register_remote_data_blocks() {
// Allow other plugins to register their blocks.
do_action( 'register_remote_data_blocks' );

self::register_blocks_for_dynamic_data_sources();
}

/**
@@ -245,4 +251,33 @@ public static function unregister_all(): void {

self::$configurations = [];
}

private static function register_blocks_for_dynamic_data_sources(): void {
$data_sources_from_config = DatasourceCRUD::get_data_sources();

foreach ( $data_sources_from_config as $_source ) {
switch ( $_source->service ) {
case 'shopify':
$datasource = new ShopifyDatasource( $_source->token, $_source->store );
$datasource->set_uuid( $_source->uuid );
$datasource->set_slug( $_source->slug );
self::register_blocks_for_shopify_data_source( $datasource );
break;
default:
break;
}
}
}

private static function register_blocks_for_shopify_data_source( ShopifyDatasource $datasource ): void {
$block_name = 'Shopify ' . $datasource->get_store_name();

$shopify_get_product_query = new ShopifyGetProductQuery( $datasource );
self::register_block( $block_name, $shopify_get_product_query );
self::$logger->debug( sprintf( 'Registered "%s" block for dynamic data source - %s', $block_name, $datasource->get_slug() ) );

$shopify_search_products_query = new ShopifySearchProductsQuery( $datasource );
self::register_search_query( $block_name, $shopify_search_products_query );
self::$logger->debug( sprintf( 'Registered "%s" _search query_ block for dynamic data source - %s', $block_name, $datasource->get_slug() ) );
}
}
3 changes: 3 additions & 0 deletions remote-data-blocks.php
Original file line number Diff line number Diff line change
@@ -26,6 +26,9 @@
require_once __DIR__ . '/inc/autoloader.php';
require_once __DIR__ . '/vendor/autoload.php';

// TODO: Figure out autoloader for this:
require_once __DIR__ . '/inc/config/dynamic-datasource-trait.php';

// Other editor modifications
Editor\AdminNotices::init();
Editor\BlockBindings::init();