moirei / laravel-google-merchant-api
Laravel Google Merchant Products API for Google Shopping.
Requires
- php: ^7.2|^8.0
- google/apiclient: ^2.4
- guzzlehttp/guzzle: ~5.3|^6.5|^7.0
- illuminate/cache: ~5.0|^6.0|^7.0|^8.0
- illuminate/support: ~5.0|^6.0|^7.0|^8.0
README
这是一个用于管理Google Shopping的Google Merchant Center数据流的精美包。该包准备实现商家高级 内容API。
使用示例
use MOIREI\GoogleMerchantApi\Facades\ProductApi; use MOIREI\GoogleMerchantApi\Facades\OrderApi; ... ProductApi::insert(function($product){ $product->offerId(1) ->title('Purple Shoes') ->description('What are thooose!!') ->price(10) ->custom('purchase_quantity_limit', 1000) ->availabilityDate( today()->addDays(7) ); })->then(function($response){ echo 'Product inserted'; })->otherwise(function($response){ echo 'Insert failed'; })->catch(function($e){ echo($e->getResponse()->getBody()->getContents()); }); OrderApi::list()->then(function($response){ // })->otherwise(function($response){ echo 'List failed'; })->catch(function($e){ echo($e->getResponse()->getBody()->getContents()); }); OrderApi::scout(); // Scout and fire event
功能
- 产品API
- 实现了
insert
、get
、delete
和list
API调用 - 使用定义的模式接口直接与eloquent模型(产品模型)一起工作
- 事件监听器以响应对eloquent模型的更改,并自动插入它们
- 实现了
- 订单API
- 实现了
acknowledge
、cancel
、cancelLineItem
、rejectReturnLineItem
、returnRefundLineItem
、get
和list
API调用。 - 内部调度器扫描未确认的订单并触发事件。这意味着您可以在Google Shopping中自动确认和注册新订单。
- 包括用于
testOrders
的沙盒功能。
- 实现了
- 多商家(1.1.0)
升级到1.1.x
尽管具有向后兼容性,但请确保更新您的配置以使用多个商家。
安装
通过composer
composer require moirei/laravel-google-merchant-api
安装服务提供者(对于Laravel>=5.5可跳过);
// config/app.php
'providers' => [
...
MOIREI\GoogleMerchantApi\GoogleMerchantApiServiceProvider::class,
],
发布配置
php artisan vendor:publish --tag="google-merchant-api-config"
设置与授权
- 请遵循此处的说明并创建一个服务帐户密钥。在您的应用程序根目录中创建
storage/app/google-merchant-api/service-account-credentials.json
并存储下载的json内容 - 获取您的商家ID
- 将您的商家ID和服务帐户凭证的路径添加到配置中
- 在配置中,如果您需要使用数组或模型,请在产品内容中设置属性部分
使用方法
多商家
从 1.1.0
开始,我们现在可以定义多个商家,并且可以通过从订单或产品API类中调用 merchant
方法在它们之间切换。
ProductApi::merchant('my-pet-store')->insert($product);
// config/laravel-google-merchant-api.php ... 'merchants' => [ 'my-pet-store' => [ 'app_name' => config('app.name'), 'merchant_id' => '000000000', 'client_credentials_path' => storage_path('app/my-pet-store-credentials.json'), ] ], ...
或者
ProductApi::merchant([ 'app_name' => 'My Pet Store', 'merchant_id' => '000000000', 'client_credentials_path' => storage_path('app/my-pet-store-credentials.json') ])->insert($product);
产品API
可以通过 insert
、get
、delete
、和 list
方法查询Google Merchant内容。产品内容由 Product
类包含和处理。可以直接传递此类的一个实例或通过闭包回调解决。可以通过以下方式填充实例:
- 直接访问底层属性。请参阅特殊函数。
- 传递一个eloquent模型,或者通过
- 传递一个原始数组
要传递一个数组或一个模型,必须在配置中定义属性关系。
插入
插入方法创建一个新的内容,如果 channel
、contentLanguage
、targetCountry
和 offerId
相同,则更新旧内容。
$attributes = [ 'id' => 1, // maps to offerId (if set in config) 'name' => 'Product 1', // likewise maps to title ]; ProductApi::insert(function($product) use($attributes){ $product->with($attributes) ->link('https://moirei.com/mg001') ->price(60, 'USD'); })->then(function($data){ echo 'Product inserted'; })->otherwise(function(){ echo 'Insert failed'; })->catch(function($e){ dump($e); });
使用数组:
use MOIREI\GoogleMerchantApi\Contents\Product\Product as GMProduct; ... $attributes = [ 'id' => 1, 'name' => 'Product 1', ]; $product = (new GMProduct)->with($attributes);
必须按照配置中的属性映射定义 attributes
值。
使用Eloquent模型:
use App\Models\Product; use MOIREI\GoogleMerchantApi\Contents\Product\Product as GMProduct; ... $model = Product::find(1); $product = (new GMProduct)->with($model); ProductApi::insert($product)->catch(function($e){ // always catch exceptions });
模型的 attributes
值必须按照配置中的属性映射进行定义。要访问未定义的模型属性,请使用访问器和自定义模型属性
protected $appends = [ 'availability', 'gm_price', ]; ... public function getAvailabilityAttribute(){ return 'in stock'; // calculate } public function getGmPriceAttribute(){ return [ 'value' => $this->price, 'currency' => $this->currency->code, ]; }
对于设置自定义产品内容(customAttributes
),您可能更倾向于使用custom()
方法。同样,对于availabilityDate
,请使用availabilityUntil()
方法。
使用事件与监听器:
提供的事件和监听器可以被设置,以便当您的应用程序创建或更新一个模型时,产品内容会自动插入。
要设置此功能,请将以下代码片段添加到您的eloquent模式中。变量product
可以是模型或数组。
use MOIREI\GoogleMerchantApi\Events\ProductCreatedOrUpdatedEvent; ... /** * The "booting" method of the model. * * @return void */ protected static function boot() { parent::boot(); // when a product is created static::created(function(Product $product){ // perhaps a logic to ignore drafts and private products if($product->is_active && (config('app.env') === 'production')){ event(new ProductCreatedOrUpdatedEvent($product)); } }); // when a product is updated static::updated(function(Product $product){ // perhaps a logic to ignore drafts and private products if($product->is_active && (config('app.env') === 'production')){ event(new ProductCreatedOrUpdatedEvent(function($gm_product) use ($product){ $gm_product->with($product) ->preorder() ->availabilityDate($product->preorder_date); })); } }); }
接下来,在EventServiceProvider.php
中定义事件关系。
use MOIREI\GoogleMerchantApi\Listeners\ProductCreatedOrUpdatedListener; ... /** * The event listener mappings for the application. * * @var array */ protected $listen = [ ..., /** * Product events */ ProductCreatedOrUpdatedEvent::class => [ ProductCreatedOrUpdatedListener::class, ], ];
获取与列表
ProductApi::get($product)->then(function($data){ // })->catch(function($e){ // always catch exceptions });
list
方法在没有任何参数的情况下调用get
方法;
ProductApi::list()->then(function($data){ // });
因此,以下代码同样可以检索产品列表
ProductApi::get()->then(function($data){ // });
删除
ProductApi::delete($product)->then(function($data){ // });
要设置事件监听器,请将以下内容添加到您的eloquent模型中
use MOIREI\GoogleMerchantApi\Events\ProductDeletedEvent; ... protected static function boot() { parent::boot(); ... // when a product is deleted static::deleted(function(Product $product){ if(config('app.env') === 'production'){ event(new ProductDeletedEvent($product)); } }); }
然后在EventServiceProvider.php
中定义关系
use MOIREI\GoogleMerchantApi\Listeners\ProductDeletedListener; ... protected $listen = [ ..., ProductDeletedEvent::class => [ ProductDeletedListener::class, ], ];
订单API
请注意,这些实现尚未经过适当测试。
使用API方法
目前实现的方法acknowledge
、cancel
、cancelLineItem
、rejectReturnLineItem
、returnRefundLineItem
、get
、list
可用于与您的Google Merchant进行交互。
使用这些方法的格式在整个包中都是标准的。例如,可以通过以下方式确认订单
OrderApi::acknowledge(function($order){ $order->id('TEST-1953-43-0514'); });
或者通过以下方式
$order = (new Order)->with([ 'id' => 'TEST-1953-43-0514', ]); OrderApi::acknowledge($order);
此外,还提供了listAcknowledged
方法,以便在需要时列出已确认的订单。
计划侦察兵
如果配置中的schedule_orders_check
设置为true,则该包将定期侦察未确认的订单,并触发一个\MOIREI\GoogleMerchantApi\Events\NewOrdersScoutedEvent
事件。该事件包含一个类为\MOIREI\GoogleMerchantApi\Contents\Order
的订单数组。订单结构遵循订单资源。
在监听器中的示例处理
use MOIREI\GoogleMerchantApi\Events\NewOrdersScoutedEvent; use MOIREI\GoogleMerchantApi\Facades\OrderApi; ... public function handle(NewOrdersScoutedEvent $event) { $merchant = $event->merchant; // array key as defined in config $merchant_id = $event->merchant_id; foreach($event->orders as $gm_order){ OrderApi::acknowledge($gm_order); $gm_order = $gm_order->all(); // get all attributes, including mutated attributes foreach($gm_order['lineItems'] as $line_item){ $model = $line_item['model']; // retrieves model $quantity = $line_item['quantityOrdered']; $shipping = $line_item['shippingDetails']; $delivery_date = $shipping['deliverByDate']->diffForHumans(); // register new order item } // register new order } }
备注:
- 访问
lineItems
将自动解析并附加相应的模型到每个项目。当然,这假设您插入的产品offerId
与模型的ID和主键相对应。 - 如果您尚未启动Laravel调度器,您需要在服务器中添加以下Cron条目。
* * * * * php artisan schedule:run >> /dev/null 2>&1
。 - 确保调度器正确设置非常重要。因此,提供了
MOIREI\GoogleMerchantApi\Events\OrderContentScoutedEvent
事件。如果配置中的debug_scout
设置为true,则每次调度器触发时都会触发此事件。
沙箱
OrderApi类提供了一种调用一些沙箱操作的方法。例如
OrderApi::sandbox()->create(function($order){ $order->shippingCost(30) ->shippingOption('economy') ->predefinedEmail('pog.dwight.schrute@gmail.com') ->predefinedDeliveryAddress('dwight'); })
您可以使用以下内容
OrderApi::sandbox()->testCreate();
来使用预设示例。
实现的沙箱操作
命令
此包提供了一个用于侦察订单的artisan命令。
php artisan gm-orders:scout
错误处理
抛出异常的方法
-
MOIREI\GoogleMerchantApi\Contents\Product::with()
如果提供的属性不是模型或数组,则抛出
MOIREI\GoogleMerchantApi\Exceptions\ProductContentAttributesUndefined
。 -
API类中的
insert
、get
、delete
、list
、listAcknowledged
和scout
方法如果客户端请求损坏、失败、未定义或未授权,将抛出GuzzleHttp\Exception\ClientException
。 -
如果将无法解析的实体传递为内容属性,则抛出
MOIREI\GoogleMerchantApi\Exceptions\Invalid**Input
异常。 -
如果无法解析商家ID或凭证路径,则
merchant
方法抛出MOIREI\GoogleMerchantApi\Exceptions\InvalidMechantDetails
。
应该使用catch
函数来处理异常。如果进行同步调用,请使用try-catch块。鉴于谷歌有千万个理由拒绝任何请求,因此强烈建议始终捕获请求(并通知您的业务逻辑)。
设计说明
- 如果使用默认的异步功能,则插入、列表、获取、删除方法将始终返回原始实例的克隆。这允许多个请求的then、otherwise和catch回调不会相互覆盖。这些方法在设置为同步模式时返回Guzzle响应。
- 如果调用删除方法且解析出的内容ID无效,则不会发起任何请求或抛出任何错误。如果调用获取方法,则返回产品或订单列表。
- 有效的产品内容ID遵循以下模式:online:en:AU:1,即
channel:contentLanguage:targetCountry:offerId
。这个ID当然是自动生成的;除了offerId
外,其他属性都有默认值。 - 请求可能需要2小时才能反映在您的Google Merchant Center上。请耐心等待!
- 与ProductApi或OrderApi类不同,事件的构造函数可以接受模型、数组或回调。
- 在
Product
、Order
或任何内容类上调用all
方法将解析所有已更改的属性。例如,$order['lineItems'][0]['shippingDetails']['deliverByDate']
返回一个Carbon
。
同步调用
以上内容默认都是异步的。要进行同步调用,请使用sync
方法
try{ $response = ProductApi::sync()->insert(function($product){ $product->offerId(1) ->country('AU') ->inStock(false); }); }catch(\GuzzleHttp\Exception\ClientException $e){ // }
注意:在这种情况下,例如insert
、get
、delete
和list
等方法,在异步调用时返回Guzzle响应(而不是ProductApi
或OrderApi
的实例。这意味着您的异常块应围绕请求进行包装。
贡献
本包旨在为Google Merchant的Google Shopping API提供Laravel解决方案。目前,只有产品内容得到了充分的实现和测试。对于订单、退款等,欢迎提出想法和pull请求。
致谢
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。