├── .github └── workflows │ ├── php-cs-fixer.yml │ └── run-tests.yml ├── .php-cs-fixer.php ├── CHANGELOG.md ├── CODEOWNERS ├── LICENSE.md ├── README.md ├── composer.json ├── config └── shopify.php └── src ├── Exceptions ├── ErrorHandlerInterface.php ├── Handler.php ├── InvalidFormatException.php ├── InvalidMethodException.php ├── NotFoundException.php ├── TooManyRequestsException.php ├── ValidationException.php └── WebhookFailed.php ├── Factory.php ├── Http ├── Controllers │ └── WebhookController.php └── Middleware │ └── ValidateWebhook.php ├── REST ├── Actions │ ├── ManagesAccess.php │ ├── ManagesAnalytics.php │ ├── ManagesBilling.php │ ├── ManagesCollections.php │ ├── ManagesCustomers.php │ ├── ManagesDiscounts.php │ ├── ManagesEvents.php │ ├── ManagesFulfillments.php │ ├── ManagesInventory.php │ ├── ManagesMarketingEvents.php │ ├── ManagesMetafields.php │ ├── ManagesOnlineStore.php │ ├── ManagesOrders.php │ ├── ManagesPlus.php │ ├── ManagesProducts.php │ ├── ManagesSalesChannel.php │ ├── ManagesShopifyPayments.php │ └── ManagesStoreProperties.php ├── Cursor.php └── Resources │ ├── ApiResource.php │ ├── ArticleResource.php │ ├── AssetResource.php │ ├── BalanceResource.php │ ├── BlogResource.php │ ├── CollectResource.php │ ├── CountryResource.php │ ├── CustomCollectionResource.php │ ├── CustomerResource.php │ ├── DisputeResource.php │ ├── DraftOrderResource.php │ ├── ImageResource.php │ ├── MetafieldResource.php │ ├── OrderResource.php │ ├── PageResource.php │ ├── PayoutResource.php │ ├── ProductResource.php │ ├── RefundResource.php │ ├── RiskResource.php │ ├── SmartCollectionResource.php │ ├── TransactionResource.php │ ├── VariantResource.php │ └── WebhookResource.php ├── Shopify.php ├── ShopifyServiceProvider.php ├── Support ├── Facades │ └── Shopify.php ├── MakesHttpRequests.php ├── TransformsResources.php └── VerifiesWebhooks.php └── Webhooks ├── ConfigSecretProvider.php ├── SecretProvider.php ├── Webhook.php └── WebhookValidator.php /.github/workflows/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | name: Check & fix styling 2 | 3 | on: push 4 | 5 | jobs: 6 | php-cs-fixer: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | with: 11 | ref: ${{ github.head_ref }} 12 | 13 | - name: Setup PHP 14 | uses: shivammathur/setup-php@v2 15 | with: 16 | php-version: 8.0 17 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, pdo_mysql, bcmath, soap, intl, gd, exif, iconv, imagick 18 | coverage: none 19 | 20 | - name: Composer install 21 | run: composer install 22 | 23 | - name: Run php-cs-fixer 24 | run: ./vendor/bin/php-cs-fixer fix 25 | 26 | - uses: stefanzweifel/git-auto-commit-action@v4 27 | with: 28 | commit_message: Apply php-cs-fixer changes 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | test: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | fail-fast: true 10 | matrix: 11 | os: [ ubuntu-latest ] 12 | php: [ 7.4, 8.0, 8.1 ] 13 | laravel: [ 8.*, 9.* ] 14 | dependency-version: [ prefer-lowest, prefer-stable ] 15 | include: 16 | - laravel: 8.* 17 | testbench: ^6.24 18 | - laravel: 9.* 19 | testbench: 7.* 20 | exclude: 21 | - laravel: 9.* 22 | php: 7.4 23 | 24 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} 25 | 26 | steps: 27 | - name: Checkout code 28 | uses: actions/checkout@v2 29 | 30 | - name: Cache dependencies 31 | uses: actions/cache@v2 32 | with: 33 | path: ~/.composer/cache/files 34 | key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 35 | 36 | - name: Setup PHP 37 | uses: shivammathur/setup-php@v2 38 | with: 39 | php-version: ${{ matrix.php }} 40 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick 41 | coverage: none 42 | 43 | - name: Install dependencies 44 | run: | 45 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update 46 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest 47 | 48 | - name: Execute tests 49 | run: vendor/bin/phpunit 50 | -------------------------------------------------------------------------------- /.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | notPath('bootstrap') 5 | ->notPath('storage') 6 | ->notPath('vendor') 7 | ->notPath('docker') 8 | ->in(getcwd()) 9 | ->name('*.php') 10 | ->notName('*.blade.php') 11 | ->notName('index.php') 12 | ->notName('server.php') 13 | ->ignoreDotFiles(true) 14 | ->ignoreVCS(true); 15 | 16 | return Signifly\styles($finder); 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-shopify` will be documented in this file 4 | 5 | ## 1.0.0 - ??? 6 | 7 | - Initial release! 8 | 9 | ## 0.0.1 - 2018-01-30 10 | 11 | - Experimental release! 12 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # More details are here: https://help.github.com/articles/about-codeowners/ 5 | 6 | # The '*' pattern is global owners. 7 | 8 | # Order is important. The last matching pattern has the most precedence. 9 | # The folders are ordered as follows: 10 | 11 | # In each subsection folders are ordered first by depth, then alphabetically. 12 | # This should make it easy to add new rules without breaking existing ones. 13 | 14 | # Global rule: 15 | * @Razorsheep -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) Signifly 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Make requests to the Shopify API from your Laravel app 6 | 7 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/signifly/laravel-shopify.svg?style=flat-square)](https://packagist.org/packages/signifly/laravel-shopify) 8 | ![Tests](https://github.com/signifly/laravel-shopify/workflows/Tests/badge.svg) 9 | ![Code Style](https://img.shields.io/github/workflow/status/signifly/laravel-shopify/Check%20&%20fix%20styling?label=code%20style) 10 | [![Quality Score](https://img.shields.io/scrutinizer/g/signifly/laravel-shopify.svg?style=flat-square)](https://scrutinizer-ci.com/g/signifly/laravel-shopify) 11 | [![Total Downloads](https://img.shields.io/packagist/dt/signifly/laravel-shopify.svg?style=flat-square)](https://packagist.org/packages/signifly/laravel-shopify) 12 | 13 | The `signifly/laravel-shopify` package allows you to easily make requests to the Shopify API. 14 | 15 | ## Installation 16 | 17 | You can install the package via composer: 18 | 19 | ```bash 20 | composer require signifly/laravel-shopify 21 | ``` 22 | 23 | The package will automatically register itself. 24 | 25 | 26 | ## Documentation 27 | 28 | You can find the full documentation here: [https://www.notion.so/signifly/Laravel-Shopify-424709fa6dd84defb0879ab8a1cb29fa](https://signifly.notion.site/Laravel-Shopify-424709fa6dd84defb0879ab8a1cb29fa?pvs=4). 29 | 30 | 31 | ## Testing 32 | ```bash 33 | composer test 34 | ``` 35 | 36 | ## Security 37 | 38 | If you discover any security issues, please email dev@signifly.com instead of using the issue tracker. 39 | 40 | ## Credits 41 | 42 | - [Morten Poul Jensen](https://github.com/pactode) 43 | - [All contributors](../../contributors) 44 | 45 | ## License 46 | 47 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 48 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "signifly/laravel-shopify", 3 | "description": "A simple package to handle communication with Shopify API", 4 | "homepage": "https://github.com/signifly/laravel-shopify", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Morten Poul Jensen", 9 | "email": "mpj@signifly.com", 10 | "role": "Developer" 11 | } 12 | ], 13 | "require": { 14 | "php": "^7.4 || ^8.0", 15 | "guzzlehttp/guzzle": "^7.2", 16 | "illuminate/contracts": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0", 17 | "illuminate/http": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0", 18 | "illuminate/routing": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0", 19 | "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0" 20 | }, 21 | "require-dev": { 22 | "friendsofphp/php-cs-fixer": "^3.0", 23 | "orchestra/testbench": "^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0", 24 | "phpunit/phpunit": "^9.0 || ^10.0 || ^11.5", 25 | "signifly/php-config": "^1.0" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Signifly\\Shopify\\": "src" 30 | } 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "Signifly\\Shopify\\Tests\\": "tests" 35 | } 36 | }, 37 | "scripts": { 38 | "test": "vendor/bin/phpunit" 39 | }, 40 | "config": { 41 | "sort-packages": true 42 | }, 43 | "extra": { 44 | "laravel": { 45 | "providers": [ 46 | "Signifly\\Shopify\\ShopifyServiceProvider" 47 | ], 48 | "aliases": { 49 | "Shopify": "Signifly\\Shopify\\Support\\Facades\\Shopify" 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /config/shopify.php: -------------------------------------------------------------------------------- 1 | [ 6 | 7 | /* 8 | * The API access token from the private app. 9 | */ 10 | 'access_token' => env('SHOPIFY_ACCESS_TOKEN', ''), 11 | 12 | /* 13 | * The shopify domain for your shop. 14 | */ 15 | 'domain' => env('SHOPIFY_DOMAIN', ''), 16 | 17 | /* 18 | * The shopify api version. 19 | */ 20 | 'api_version' => env('SHOPIFY_API_VERSION', '2021-01'), 21 | 22 | ], 23 | 24 | 'webhooks' => [ 25 | 26 | /* 27 | * The webhook secret provider to use. 28 | */ 29 | 'secret_provider' => Signifly\Shopify\Webhooks\ConfigSecretProvider::class, 30 | 31 | /* 32 | * The shopify webhook secret. 33 | */ 34 | 'secret' => env('SHOPIFY_WEBHOOK_SECRET'), 35 | 36 | ], 37 | 38 | 'exceptions' => [ 39 | 40 | /* 41 | * Whether to include the validation errors in the exception message. 42 | */ 43 | 'include_validation_errors' => false, 44 | 45 | ], 46 | ]; 47 | -------------------------------------------------------------------------------- /src/Exceptions/ErrorHandlerInterface.php: -------------------------------------------------------------------------------- 1 | successful()) { 13 | return; 14 | } 15 | 16 | if ($response->status() === 429) { 17 | throw new TooManyRequestsException($response); 18 | } 19 | 20 | if ($response->status() === 422) { 21 | throw new ValidationException(Arr::wrap($response->json('errors', []))); 22 | } 23 | 24 | if ($response->status() === 404) { 25 | throw new NotFoundException(); 26 | } 27 | 28 | $response->throw(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidFormatException.php: -------------------------------------------------------------------------------- 1 | response = $response; 14 | 15 | parent::__construct($message ?? 'Too many requests.'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Exceptions/ValidationException.php: -------------------------------------------------------------------------------- 1 | errors = $errors; 12 | 13 | parent::__construct( 14 | config('shopify.exceptions.include_validation_errors', false) 15 | ? 'Validation failed due to: '.json_encode($this->errors) 16 | : 'The given data failed to pass validation.' 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Exceptions/WebhookFailed.php: -------------------------------------------------------------------------------- 1 | $this->getMessage()], 400); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Factory.php: -------------------------------------------------------------------------------- 1 | middleware(ValidateWebhook::class); 20 | } 21 | 22 | public function handle(Request $request) 23 | { 24 | try { 25 | $webhook = Webhook::fromRequest($request); 26 | 27 | Event::dispatch($webhook->eventName(), $webhook); 28 | 29 | return new JsonResponse(); 30 | } catch (Exception $e) { 31 | Log::error($e->getMessage()); 32 | 33 | return new Response('Error handling webhook', 500); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Http/Middleware/ValidateWebhook.php: -------------------------------------------------------------------------------- 1 | webhookValidator = $webhookValidator; 16 | } 17 | 18 | public function handle(Request $request, Closure $next) 19 | { 20 | $this->webhookValidator->validateFromRequest($request); 21 | 22 | return $next($request); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesAccess.php: -------------------------------------------------------------------------------- 1 | post('custom_collections.json', ['custom_collection' => $data]); 20 | 21 | return new CustomCollectionResource($response['custom_collection'], $this); 22 | } 23 | 24 | public function getCustomCollectionsCount(array $params = []): int 25 | { 26 | $response = $this->get('custom_collections/count.json', $params); 27 | 28 | return $response['count'] ?? 0; 29 | } 30 | 31 | public function paginateCustomCollections(array $params): Cursor 32 | { 33 | return $this->cursor($this->getCustomCollections($params)); 34 | } 35 | 36 | public function getCustomCollections(array $params = []): Collection 37 | { 38 | $response = $this->get('custom_collections.json', $params); 39 | 40 | return $this->transformCollection($response['custom_collections'], CustomCollectionResource::class); 41 | } 42 | 43 | public function getCustomCollection($collectionId): CustomCollectionResource 44 | { 45 | $response = $this->get("custom_collections/{$collectionId}.json"); 46 | 47 | return new CustomCollectionResource($response['custom_collection'], $this); 48 | } 49 | 50 | public function updateCustomCollection($collectionId, array $data): CustomCollectionResource 51 | { 52 | $response = $this->put("custom_collections/{$collectionId}.json", ['custom_collection' => $data]); 53 | 54 | return new CustomCollectionResource($response['custom_collection'], $this); 55 | } 56 | 57 | public function deleteCustomCollection($collectionId): void 58 | { 59 | $this->delete("custom_collections/{$collectionId}.json"); 60 | } 61 | 62 | public function createSmartCollection(array $data): SmartCollectionResource 63 | { 64 | $response = $this->post('smart_collections.json', ['smart_collection' => $data]); 65 | 66 | return new SmartCollectionResource($response['smart_collection'], $this); 67 | } 68 | 69 | public function getSmartCollectionsCount(array $params = []): int 70 | { 71 | $response = $this->get('smart_collections/count.json', $params); 72 | 73 | return $response['count'] ?? 0; 74 | } 75 | 76 | public function getSmartCollections(array $params = []): Collection 77 | { 78 | $response = $this->get('smart_collections.json', $params); 79 | 80 | return $this->transformCollection($response['smart_collections'], SmartCollectionResource::class); 81 | } 82 | 83 | public function getSmartCollection($collectionId): SmartCollectionResource 84 | { 85 | $response = $this->get("smart_collections/{$collectionId}.json"); 86 | 87 | return new SmartCollectionResource($response['smart_collection'], $this); 88 | } 89 | 90 | public function updateSmartCollection($collectionId, array $data): SmartCollectionResource 91 | { 92 | $response = $this->put("smart_collections/{$collectionId}.json", ['smart_collection' => $data]); 93 | 94 | return new SmartCollectionResource($response['smart_collection'], $this); 95 | } 96 | 97 | public function deleteSmartCollection($collectionId): void 98 | { 99 | $this->delete("smart_collections/{$collectionId}.json"); 100 | } 101 | 102 | public function reorderSmartCollection($collectionId, array $productIds) 103 | { 104 | $response = $this->put("smart_collections/{$collectionId}/order.json", ['products' => $productIds]); 105 | 106 | return new SmartCollectionResource($response['smart_collection'], $this); 107 | } 108 | 109 | public function createCollect(array $data): CollectResource 110 | { 111 | $response = $this->post('collects.json', ['collect' => $data]); 112 | 113 | return new CollectResource($response['collect'], $this); 114 | } 115 | 116 | public function getCollectsCount(array $params = []): int 117 | { 118 | $response = $this->get('collects/count.json', $params); 119 | 120 | return $response['count'] ?? 0; 121 | } 122 | 123 | public function getCollects(array $params = []): Collection 124 | { 125 | $response = $this->get('collects.json', $params); 126 | 127 | return $this->transformCollection($response['collects'], CollectResource::class); 128 | } 129 | 130 | public function deleteCollect($collectId): void 131 | { 132 | $this->delete("collects/{$collectId}.json"); 133 | } 134 | 135 | public function getCollection($collectionId): ApiResource 136 | { 137 | $response = $this->get("collections/{$collectionId}.json"); 138 | 139 | return new ApiResource($response['collection'], $this); 140 | } 141 | 142 | public function getCollectionProducts($collectionId, array $params = []): Collection 143 | { 144 | $response = $this->get("collections/{$collectionId}/products.json", $params); 145 | 146 | return $this->transformCollection($response['products'], ProductResource::class); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesCustomers.php: -------------------------------------------------------------------------------- 1 | createResource('customers', $data); 17 | } 18 | 19 | public function getCustomersCount(array $params = []): int 20 | { 21 | return $this->getResourceCount('customers', $params); 22 | } 23 | 24 | public function paginateSearchCustomers(string $query, array $params = []): Cursor 25 | { 26 | return $this->cursor($this->searchCustomers($query, $params)); 27 | } 28 | 29 | public function searchCustomers(string $query, array $params = []): Collection 30 | { 31 | $response = $this->get('customers/search.json', ['query' => $query] + $params); 32 | 33 | return $this->transformCollection($response['customers'], CustomerResource::class); 34 | } 35 | 36 | public function paginateCustomers(array $params = []): Cursor 37 | { 38 | return $this->cursor($this->getCustomers($params)); 39 | } 40 | 41 | public function getCustomers(array $params = []): Collection 42 | { 43 | return $this->getResources('customers', $params); 44 | } 45 | 46 | public function getCustomer($customerId): CustomerResource 47 | { 48 | return $this->getResource('customers', $customerId); 49 | } 50 | 51 | public function updateCustomer($customerId, $data): CustomerResource 52 | { 53 | return $this->updateResource('customers', $customerId, $data); 54 | } 55 | 56 | public function deleteCustomer($customerId): void 57 | { 58 | $this->deleteResource('customers', $customerId); 59 | } 60 | 61 | public function createCustomerAccountActivationUrl($customerId): string 62 | { 63 | return $this->post("customers/{$customerId}/account_activation_url.json")['account_activation_url']; 64 | } 65 | 66 | public function sendCustomerInvite($customerId, array $data = []): ApiResource 67 | { 68 | $response = $this->post("customers/{$customerId}/send_invite.json", ['customer_invite' => $data]); 69 | 70 | return new ApiResource($response['customer_invite'], $this); 71 | } 72 | 73 | public function paginateCustomerOrders($customerId, array $params = []): Cursor 74 | { 75 | return $this->cursor($this->getCustomerOrders($customerId, $params)); 76 | } 77 | 78 | public function getCustomerOrders($customerId, array $params = []): Collection 79 | { 80 | return $this->getResources('orders', $params, ['customers', $customerId]); 81 | } 82 | 83 | public function createCustomerAddress($customerId, array $data): ApiResource 84 | { 85 | return $this->createResource('addresses', $data, ['customers', $customerId], 'customer_address'); 86 | } 87 | 88 | public function getCustomerAddresses($customerId, array $params = []): Collection 89 | { 90 | return $this->getResources('addresses', $params, ['customers', $customerId]); 91 | } 92 | 93 | public function getCustomerAddress($customerId, $addressId): ApiResource 94 | { 95 | return $this->getResource('addresses', $addressId, ['customers', $customerId]); 96 | } 97 | 98 | public function updateCustomerAddress($customerId, $addressId, $data): ApiResource 99 | { 100 | return $this->updateResource('addresses', $addressId, $data, ['customers', $customerId], 'customer_address'); 101 | } 102 | 103 | public function deleteCustomerAddress($customerId, $addressId): void 104 | { 105 | $this->deleteResource('addresses', $addressId, ['customers', $customerId]); 106 | } 107 | 108 | public function setDefaultCustomerAddress($customerId, $addressId): ApiResource 109 | { 110 | $response = $this->put("customers/{$customerId}/addresses/{$addressId}/default.json"); 111 | 112 | return new ApiResource($response['customer_address'], $this); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesDiscounts.php: -------------------------------------------------------------------------------- 1 | createResource('discount_codes', ['code' => $code], ['price_rules', $priceRuleId]); 15 | } 16 | 17 | public function getDiscountCodesCount(array $params = []): int 18 | { 19 | return $this->getResourceCount('discount_codes', $params); 20 | } 21 | 22 | public function getDiscountCodes($priceRuleId, array $params = []): Collection 23 | { 24 | return $this->getResources('discount_codes', $params, ['price_rules', $priceRuleId]); 25 | } 26 | 27 | public function getDiscountCode($priceRuleId, $discountCodeId): ApiResource 28 | { 29 | return $this->getResource('discount_codes', $discountCodeId, ['price_rules', $priceRuleId]); 30 | } 31 | 32 | public function updateDiscountCode($priceRuleId, $discountCodeId, string $code): ApiResource 33 | { 34 | return $this->updateResource('discount_codes', $discountCodeId, ['code' => $code], ['price_rules', $priceRuleId]); 35 | } 36 | 37 | public function deleteDiscountCode($priceRuleId, $discountCodeId): void 38 | { 39 | $this->deleteResource('discount_codes', $discountCodeId, ['price_rules', $priceRuleId]); 40 | } 41 | 42 | public function createPriceRule(array $data): ApiResource 43 | { 44 | return $this->createResource('price_rules', $data); 45 | } 46 | 47 | public function getPriceRulesCount(array $params = []): int 48 | { 49 | return $this->getResourceCount('price_rules', $params); 50 | } 51 | 52 | public function paginatePriceRules(array $params = []): Cursor 53 | { 54 | return $this->cursor($this->getPriceRules($params)); 55 | } 56 | 57 | public function getPriceRules(array $params = []): Collection 58 | { 59 | return $this->getResources('price_rules', $params); 60 | } 61 | 62 | public function getPriceRule($priceRuleId): ApiResource 63 | { 64 | return $this->getResource('price_rules', $priceRuleId); 65 | } 66 | 67 | public function updatePriceRule($priceRuleId, $data): ApiResource 68 | { 69 | return $this->updateResource('price_rules', $priceRuleId, $data); 70 | } 71 | 72 | public function deletePriceRule($priceRuleId): void 73 | { 74 | $this->deleteResource('price_rules', $priceRuleId); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesEvents.php: -------------------------------------------------------------------------------- 1 | createResource('events', $data); 17 | } 18 | 19 | public function getEventsCount(array $params = []): int 20 | { 21 | return $this->getResourceCount('events', $params); 22 | } 23 | 24 | public function paginateEvents(array $params = []): Cursor 25 | { 26 | return $this->cursor($this->getEvents($params)); 27 | } 28 | 29 | public function getEvents(array $params = []): Collection 30 | { 31 | return $this->getResources('events', $params); 32 | } 33 | 34 | public function createWebhook(array $data): WebhookResource 35 | { 36 | return $this->createResource('webhooks', $data); 37 | } 38 | 39 | public function getWebhooksCount(array $params = []): int 40 | { 41 | return $this->getResourceCount('webhooks', $params); 42 | } 43 | 44 | public function paginateWebhooks(array $params = []): Cursor 45 | { 46 | return $this->cursor($this->getWebhooks($params)); 47 | } 48 | 49 | public function getWebhooks(array $params = []): Collection 50 | { 51 | return $this->getResources('webhooks', $params); 52 | } 53 | 54 | public function getWebhook($webhookId): WebhookResource 55 | { 56 | return $this->getResource('webhooks', $webhookId); 57 | } 58 | 59 | public function updateWebhook($webhookId, $data): WebhookResource 60 | { 61 | return $this->updateResource('webhooks', $webhookId, $data); 62 | } 63 | 64 | public function deleteWebhook($webhookId): void 65 | { 66 | $this->deleteResource('webhooks', $webhookId); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesFulfillments.php: -------------------------------------------------------------------------------- 1 | getResourceCount('fulfillments', $params, ['orders', $orderId]); 15 | } 16 | 17 | public function getOrderFulfillments($orderId, array $params = []): Collection 18 | { 19 | return $this->getResources('fulfillments', $params, ['orders', $orderId]); 20 | } 21 | 22 | public function getOrderFulfillment($orderId, $fulfillmentId): ApiResource 23 | { 24 | return $this->getResource('fulfillments', $fulfillmentId, ['orders', $orderId]); 25 | } 26 | 27 | public function createFulfillment(array $data): ApiResource 28 | { 29 | return $this->createResource('fulfillments', $data); 30 | } 31 | 32 | public function updateOrderFulfillment($orderId, $fulfillmentId, array $data): ApiResource 33 | { 34 | return $this->updateResource('fulfillments', $fulfillmentId, $data, ['orders', $orderId]); 35 | } 36 | 37 | public function updateTrackingForFulfillment($fulfillmentId, array $data): ApiResource 38 | { 39 | $response = $this->post("fulfillments/{$fulfillmentId}/update_tracking.json", $data); 40 | 41 | return new ApiResource($response['fulfillment'], $this); 42 | } 43 | 44 | public function completeOrderFulfillment($orderId, $fulfillmentId): ApiResource 45 | { 46 | $response = $this->post("orders/{$orderId}/fulfillments/{$fulfillmentId}/complete.json"); 47 | 48 | return new ApiResource($response['fulfillment'], $this); 49 | } 50 | 51 | public function openOrderFulfillment($orderId, $fulfillmentId): ApiResource 52 | { 53 | $response = $this->post("orders/{$orderId}/fulfillments/{$fulfillmentId}/open.json"); 54 | 55 | return new ApiResource($response['fulfillment'], $this); 56 | } 57 | 58 | public function cancelOrderFulfillment($orderId, $fulfillmentId): ApiResource 59 | { 60 | $response = $this->post("orders/{$orderId}/fulfillments/{$fulfillmentId}/cancel.json"); 61 | 62 | return new ApiResource($response['fulfillment'], $this); 63 | } 64 | 65 | public function cancelFulfillment($fulfillmentId): ApiResource 66 | { 67 | $response = $this->post("fulfillments/{$fulfillmentId}/cancel.json"); 68 | 69 | return new ApiResource($response['fulfillment'], $this); 70 | } 71 | 72 | public function getFulfillmentOrderFulfillments($fulfillmentOrderId, array $params = []): Collection 73 | { 74 | return $this->getResources('fulfillments', $params, ['fulfillment_orders', $fulfillmentOrderId]); 75 | } 76 | 77 | public function getOrderFulfillmentEvents($orderId, $fulfillmentId, array $params = []): Collection 78 | { 79 | return $this->getResources('events', $params, ['orders', $orderId, 'fulfillments', $fulfillmentId]); 80 | } 81 | 82 | public function getOrderFulfillmentEvent($orderId, $fulfillmentId, $eventId): ApiResource 83 | { 84 | return $this->getResource('events', $eventId, ['orders', $orderId, 'fulfillments', $fulfillmentId]); 85 | } 86 | 87 | public function createOrderFulfillmentEvent($orderId, $fulfillmentId, array $data): ApiResource 88 | { 89 | return $this->createResource('events', $data, ['orders', $orderId, 'fulfillments', $fulfillmentId]); 90 | } 91 | 92 | public function deleteOrderFulfillmentEvent($orderId, $fulfillmentId, $eventId): void 93 | { 94 | $this->deleteResource('events', $eventId, ['orders', $orderId, 'fulfillments', $fulfillmentId]); 95 | } 96 | 97 | public function getOrderFulfillmentOrders($orderId, array $params = []): Collection 98 | { 99 | return $this->getResources('fulfillment_orders', $params, ['orders', $orderId]); 100 | } 101 | 102 | public function getFulfillmentOrder($fulfillmentOrderId): ApiResource 103 | { 104 | return $this->getResource('fulfillment_orders', $fulfillmentOrderId); 105 | } 106 | 107 | public function cancelFulfillmentOrder($fulfillmentOrderId): ApiResource 108 | { 109 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/cancel.json"); 110 | 111 | return new ApiResource($response['fulfillment_order'], $this); 112 | } 113 | 114 | public function closeFulfillmentOrder($fulfillmentOrderId, array $data): ApiResource 115 | { 116 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/close.json", [ 117 | 'fulfillment_order' => $data, 118 | ]); 119 | 120 | return new ApiResource($response['fulfillment_order'], $this); 121 | } 122 | 123 | public function moveFulfillmentOrder($fulfillmentOrderId, array $data): ApiResource 124 | { 125 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/close.json", [ 126 | 'fulfillment_order' => $data, 127 | ]); 128 | 129 | return new ApiResource($response['fulfillment_order'], $this); 130 | } 131 | 132 | public function getFulfillmentOrderLocationsForMove($fulfillmentOrderId, array $params = []): Collection 133 | { 134 | return $this->getResources('locations_for_move', $params, ['fulfillment_orders', $fulfillmentOrderId]); 135 | } 136 | 137 | public function sendFulfillmentOrderFulfillmentRequest($fulfillmentOrderId, array $data = []): ApiResource 138 | { 139 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/fulfillment_request.json", [ 140 | 'fulfillment_request' => $data, 141 | ]); 142 | 143 | return new ApiResource($response['original_fulfillment_order'], $this); 144 | } 145 | 146 | public function acceptFulfillmentOrderFulfillmentRequest($fulfillmentOrderId, array $data = []): ApiResource 147 | { 148 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/fulfillment_request/accept.json", [ 149 | 'fulfillment_request' => $data, 150 | ]); 151 | 152 | return new ApiResource($response['fulfillment_order'], $this); 153 | } 154 | 155 | public function rejectFulfillmentOrderFulfillmentRequest($fulfillmentOrderId, array $data = []): ApiResource 156 | { 157 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/fulfillment_request/reject.json", [ 158 | 'fulfillment_request' => $data, 159 | ]); 160 | 161 | return new ApiResource($response['fulfillment_order'], $this); 162 | } 163 | 164 | public function createFulfillmentService(array $data): ApiResource 165 | { 166 | return $this->createResource('fulfillment_services', $data); 167 | } 168 | 169 | public function getFulfillmentServices(array $params = []): Collection 170 | { 171 | return $this->getResources('fulfillment_services', $params); 172 | } 173 | 174 | public function getFulfillmentService($fulfillmentServiceId): ApiResource 175 | { 176 | return $this->getResource('fulfillment_services', $fulfillmentServiceId); 177 | } 178 | 179 | public function updateFulfillmentService($fulfillmentServiceId, array $data): ApiResource 180 | { 181 | return $this->updateResource('fulfillment_services', $fulfillmentServiceId, $data); 182 | } 183 | 184 | public function deleteFulfillmentService($fulfillmentServiceId): void 185 | { 186 | $this->deleteResource('fulfillment_services', $fulfillmentServiceId); 187 | } 188 | 189 | public function createCarrierService(array $data): ApiResource 190 | { 191 | return $this->createResource('carrier_services', $data); 192 | } 193 | 194 | public function getCarrierServices(array $params = []): Collection 195 | { 196 | return $this->getResources('carrier_services', $params); 197 | } 198 | 199 | public function getCarrierService($carrierServiceId): ApiResource 200 | { 201 | return $this->getResource('carrier_services', $carrierServiceId); 202 | } 203 | 204 | public function updateCarrierService($carrierServiceId, array $data): ApiResource 205 | { 206 | return $this->updateResource('carrier_services', $carrierServiceId, $data); 207 | } 208 | 209 | public function deleteCarrierService($carrierServiceId): void 210 | { 211 | $this->deleteResource('carrier_services', $carrierServiceId); 212 | } 213 | 214 | public function sendFulfillmentOrderCancellationRequest($fulfillmentOrderId, array $data = []): ApiResource 215 | { 216 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/cancellation_request.json", [ 217 | 'cancellation_request' => $data, 218 | ]); 219 | 220 | return new ApiResource($response['fulfillment_order'], $this); 221 | } 222 | 223 | public function acceptFulfillmentOrderCancellationRequest($fulfillmentOrderId, array $data = []): ApiResource 224 | { 225 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/cancellation_request/accept.json", [ 226 | 'cancellation_request' => $data, 227 | ]); 228 | 229 | return new ApiResource($response['fulfillment_order'], $this); 230 | } 231 | 232 | public function rejectFulfillmentOrderCancellationRequest($fulfillmentOrderId, array $data = []): ApiResource 233 | { 234 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/cancellation_request/reject.json", [ 235 | 'cancellation_request' => $data, 236 | ]); 237 | 238 | return new ApiResource($response['fulfillment_order'], $this); 239 | } 240 | 241 | public function getAssignedFulfillmentOrders(string $assignmentStatus, array $locationIds): Collection 242 | { 243 | $response = $this->get('assigned_fulfillment_orders.json', [ 244 | 'assignment_status' => $assignmentStatus, 245 | 'location_ids%5B%5D' => $locationIds, 246 | ]); 247 | 248 | return $this->transformCollection($response['fulfillment_orders'], ApiResource::class); 249 | } 250 | 251 | public function holdFulfillmentOrder($fulfillmentOrderId, array $data): ApiResource 252 | { 253 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/hold.json", [ 254 | 'fulfillment_hold' => $data, 255 | ]); 256 | 257 | return new ApiResource($response['fulfillment_order'], $this); 258 | } 259 | 260 | public function openFulfillmentOrder($fulfillmentOrderId): ApiResource 261 | { 262 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/close.json"); 263 | 264 | return new ApiResource($response['fulfillment_order'], $this); 265 | } 266 | 267 | public function releaseHoldFulfillmentOrder($fulfillmentOrderId): ApiResource 268 | { 269 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/release_hold.json"); 270 | 271 | return new ApiResource($response['fulfillment_order'], $this); 272 | } 273 | 274 | public function rescheduleFulfillmentOrder($fulfillmentOrderId, $data): ApiResource 275 | { 276 | $response = $this->post("fulfillment_orders/{$fulfillmentOrderId}/reschedule.json", $data); 277 | 278 | return new ApiResource($response['fulfillment_order'], $this); 279 | } 280 | 281 | public function setFulfillmentOrdersDeadline(array $fulfillmentOrderIds, $fulfillmentDeadline): bool 282 | { 283 | $response = $this->post('fulfillment_orders/set_fulfillment_orders_deadline.json', [ 284 | 'fulfillment_order_ids' => $fulfillmentOrderIds, 285 | 'fulfillment_deadline' => $fulfillmentDeadline, 286 | ]); 287 | 288 | return true; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesInventory.php: -------------------------------------------------------------------------------- 1 | get('inventory_items.json', $params); 15 | 16 | return $this->transformCollection($response['inventory_items'], ApiResource::class); 17 | } 18 | 19 | public function getInventoryItem($inventoryItemId): ApiResource 20 | { 21 | $response = $this->get("inventory_items/{$inventoryItemId}.json"); 22 | 23 | return new ApiResource($response['inventory_item'], $this); 24 | } 25 | 26 | public function updateInventoryItem($inventoryItemId, array $data): ApiResource 27 | { 28 | $response = $this->put("inventory_items/{$inventoryItemId}.json", ['inventory_item' => $data]); 29 | 30 | return new ApiResource($response['inventory_item'], $this); 31 | } 32 | 33 | public function getInventoryLevels(array $params = []): Collection 34 | { 35 | $response = $this->get('inventory_levels.json', $params); 36 | 37 | return $this->transformCollection($response['inventory_levels'], ApiResource::class); 38 | } 39 | 40 | public function deleteInventoryLevel($inventoryItemId, $locationId): void 41 | { 42 | $this->delete('inventory_levels.json', [ 43 | 'inventory_item_id' => $inventoryItemId, 44 | 'location_id' => $locationId, 45 | ]); 46 | } 47 | 48 | public function adjustInventoryLevel($inventoryItemId, $locationId, int $availableAdjustment): ApiResource 49 | { 50 | $response = $this->post('inventory_levels/adjust.json', [ 51 | 'inventory_item_id' => $inventoryItemId, 52 | 'location_id' => $locationId, 53 | 'available_adjustment' => $availableAdjustment, 54 | ]); 55 | 56 | return new ApiResource($response['inventory_level'], $this); 57 | } 58 | 59 | public function connectInventoryLevel($inventoryItemId, $locationId, bool $relocate = false): ApiResource 60 | { 61 | $response = $this->post('inventory_levels/connect.json', [ 62 | 'inventory_item_id' => $inventoryItemId, 63 | 'location_id' => $locationId, 64 | 'relocate_if_necessary' => $relocate, 65 | ]); 66 | 67 | return new ApiResource($response['inventory_level'], $this); 68 | } 69 | 70 | public function setInventoryLevel($inventoryItemId, $locationId, int $available, bool $disconnect = false): ApiResource 71 | { 72 | $response = $this->post('inventory_levels/set.json', [ 73 | 'inventory_item_id' => $inventoryItemId, 74 | 'location_id' => $locationId, 75 | 'available' => $available, 76 | 'disconnect_if_necessary' => $disconnect, 77 | ]); 78 | 79 | return new ApiResource($response['inventory_level'], $this); 80 | } 81 | 82 | public function getLocationsCount(array $params = []): int 83 | { 84 | $response = $this->get('locations/count.json', $params); 85 | 86 | return $response['count'] ?? 0; 87 | } 88 | 89 | public function getLocations(array $params = []): Collection 90 | { 91 | $response = $this->get('locations.json', $params); 92 | 93 | return $this->transformCollection($response['locations'], ApiResource::class); 94 | } 95 | 96 | public function getLocation($locationId): ApiResource 97 | { 98 | $response = $this->get("locations/{$locationId}.json"); 99 | 100 | return $this->transformItem($response['location'], ApiResource::class); 101 | } 102 | 103 | public function getLocationInventoryLevels($locationId, array $params = []): Collection 104 | { 105 | $response = $this->get("locations/{$locationId}/inventory_levels.json", $params); 106 | 107 | return $this->transformCollection($response['inventory_levels'], ApiResource::class); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesMarketingEvents.php: -------------------------------------------------------------------------------- 1 | createResource('metafields', $data); 15 | } 16 | 17 | public function getMetafieldsCount(array $params = []): int 18 | { 19 | return $this->getResourceCount('metafields', $params); 20 | } 21 | 22 | public function getMetafields(array $params = []): Collection 23 | { 24 | return $this->getResources('metafields', $params); 25 | } 26 | 27 | public function getMetafield($metafieldId): MetafieldResource 28 | { 29 | return $this->getResource('metafields', $metafieldId); 30 | } 31 | 32 | public function updateMetafield($metafieldId, array $data): MetafieldResource 33 | { 34 | return $this->updateResource('metafields', $metafieldId, $data); 35 | } 36 | 37 | public function deleteMetafield($metafieldId): void 38 | { 39 | $this->deleteResource('metafields', $metafieldId); 40 | } 41 | 42 | public function createCustomerMetafield($customerId, array $data): MetafieldResource 43 | { 44 | return $this->createResource('metafields', $data, ['customers', $customerId]); 45 | } 46 | 47 | public function getCustomerMetafieldsCount($customerId, array $params = []): int 48 | { 49 | return $this->getResourceCount('metafields', $params, ['customers', $customerId]); 50 | } 51 | 52 | public function getCustomerMetafields($customerId, array $params = []): Collection 53 | { 54 | return $this->getResources('metafields', $params, ['customers', $customerId]); 55 | } 56 | 57 | public function createProductMetafield($productId, array $data): MetafieldResource 58 | { 59 | return $this->createResource('metafields', $data, ['products', $productId]); 60 | } 61 | 62 | public function getProductMetafieldsCount($productId, array $params = []): int 63 | { 64 | return $this->getResourceCount('metafields', $params, ['products', $productId]); 65 | } 66 | 67 | public function getProductMetafields($productId, array $params = []): Collection 68 | { 69 | return $this->getResources('metafields', $params, ['products', $productId]); 70 | } 71 | 72 | public function createVariantMetafield($variantId, array $data): MetafieldResource 73 | { 74 | return $this->createResource('metafields', $data, ['variants', $variantId]); 75 | } 76 | 77 | public function getVariantMetafieldsCount($variantId, array $params = []): int 78 | { 79 | return $this->getResourceCount('metafields', $params, ['variants', $variantId]); 80 | } 81 | 82 | public function getVariantMetafields($variantId, array $params = []): Collection 83 | { 84 | return $this->getResources('metafields', $params, ['variants', $variantId]); 85 | } 86 | 87 | public function createProductVariantMetafield($productId, $variantId, array $data): MetafieldResource 88 | { 89 | return $this->createResource('metafields', $data, ['products', $productId, 'variants', $variantId]); 90 | } 91 | 92 | public function getProductVariantMetafieldsCount($productId, $variantId, array $params = []): int 93 | { 94 | return $this->getResourceCount('metafields', $params, ['products', $productId, 'variants', $variantId]); 95 | } 96 | 97 | public function getProductVariantMetafields($productId, $variantId, array $params = []): Collection 98 | { 99 | return $this->getResources('metafields', $params, ['products', $productId, 'variants', $variantId]); 100 | } 101 | 102 | public function createDraftOrderMetafield($orderId, array $data): MetafieldResource 103 | { 104 | return $this->createResource('metafields', $data, ['draft_orders', $orderId]); 105 | } 106 | 107 | public function getDraftOrderMetafieldsCount($orderId, array $params = []): int 108 | { 109 | return $this->getResourceCount('metafields', $params, ['draft_orders', $orderId]); 110 | } 111 | 112 | public function getDraftOrderMetafields($orderId, array $params = []): Collection 113 | { 114 | return $this->getResources('metafields', $params, ['draft_orders', $orderId]); 115 | } 116 | 117 | public function createOrderMetafield($orderId, array $data): MetafieldResource 118 | { 119 | return $this->createResource('metafields', $data, ['orders', $orderId]); 120 | } 121 | 122 | public function getOrderMetafieldsCount($orderId, array $params = []): int 123 | { 124 | return $this->getResourceCount('metafields', $params, ['orders', $orderId]); 125 | } 126 | 127 | public function getOrderMetafields($orderId, array $params = []): Collection 128 | { 129 | return $this->getResources('metafields', $params, ['orders', $orderId]); 130 | } 131 | 132 | public function createCollectionMetafield($collectionId, array $data): MetafieldResource 133 | { 134 | return $this->createResource('metafields', $data, ['collections', $collectionId]); 135 | } 136 | 137 | public function getCollectionMetafieldsCount($collectionId, array $params = []): int 138 | { 139 | return $this->getResourceCount('metafields', $params, ['collections', $collectionId]); 140 | } 141 | 142 | public function getCollectionMetafields($collectionId, array $params = []): Collection 143 | { 144 | return $this->getResources('metafields', $params, ['collections', $collectionId]); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesOnlineStore.php: -------------------------------------------------------------------------------- 1 | createResource('redirects', [ 20 | 'path' => $path, 21 | 'target' => $target, 22 | ]); 23 | } 24 | 25 | public function getRedirectsCount(array $params = []): int 26 | { 27 | return $this->getResourceCount('redirects', $params); 28 | } 29 | 30 | public function paginateRedirects(array $params = []): Cursor 31 | { 32 | return $this->cursor($this->getRedirects($params)); 33 | } 34 | 35 | public function getRedirects(array $params = []): Collection 36 | { 37 | return $this->getResources('redirects', $params); 38 | } 39 | 40 | public function getRedirect($redirectId): ApiResource 41 | { 42 | return $this->getResource('redirects', $redirectId); 43 | } 44 | 45 | public function updateRedirect($redirectId, $data): ApiResource 46 | { 47 | return $this->updateResource('redirects', $redirectId, $data); 48 | } 49 | 50 | public function deleteRedirect($redirectId): void 51 | { 52 | $this->deleteResource('redirects', $redirectId); 53 | } 54 | 55 | public function createBlog(array $data): BlogResource 56 | { 57 | return $this->createResource('blogs', $data); 58 | } 59 | 60 | public function getBlogsCount(array $params = []): int 61 | { 62 | return $this->getResourceCount('blogs', $params); 63 | } 64 | 65 | public function paginateBlogs(array $params = []): Cursor 66 | { 67 | return $this->cursor($this->getBlogs($params)); 68 | } 69 | 70 | public function getBlogs(array $params = []): Collection 71 | { 72 | return $this->getResources('blogs', $params); 73 | } 74 | 75 | public function getBlog($blogId): BlogResource 76 | { 77 | return $this->getResource('blogs', $blogId); 78 | } 79 | 80 | public function updateBlog($blogId, $data): BlogResource 81 | { 82 | return $this->updateResource('blogs', $blogId, $data); 83 | } 84 | 85 | public function deleteBlog($blogId): void 86 | { 87 | $this->deleteResource('blogs', $blogId); 88 | } 89 | 90 | public function createPage(array $data): PageResource 91 | { 92 | return $this->createResource('pages', $data); 93 | } 94 | 95 | public function getPagesCount(array $params = []): int 96 | { 97 | return $this->getResourceCount('pages', $params); 98 | } 99 | 100 | public function paginatePages(array $params = []): Cursor 101 | { 102 | return $this->cursor($this->getPages($params)); 103 | } 104 | 105 | public function getPages(array $params = []): Collection 106 | { 107 | return $this->getResources('pages', $params); 108 | } 109 | 110 | public function getPage($pageId): PageResource 111 | { 112 | return $this->getResource('pages', $pageId); 113 | } 114 | 115 | public function updatePage($pageId, $data): PageResource 116 | { 117 | return $this->updateResource('pages', $pageId, $data); 118 | } 119 | 120 | public function deletePage($pageId): void 121 | { 122 | $this->deleteResource('pages', $pageId); 123 | } 124 | 125 | public function createArticle(array $data): ArticleResource 126 | { 127 | return $this->createResource('articles', $data); 128 | } 129 | 130 | public function getArticlesCount(array $params = []): int 131 | { 132 | return $this->getResourceCount('articles', $params); 133 | } 134 | 135 | public function paginateArticles(array $params = []): Cursor 136 | { 137 | return $this->cursor($this->getArticles($params)); 138 | } 139 | 140 | public function getArticles(array $params = []): Collection 141 | { 142 | return $this->getResources('articles', $params); 143 | } 144 | 145 | public function getArticleAuthors(): array 146 | { 147 | $response = $this->get('articles/authors.json'); 148 | 149 | return $response->json('authors'); 150 | } 151 | 152 | public function getArticleTags(array $params = []): array 153 | { 154 | $response = $this->get('articles/tags.json', $params); 155 | 156 | return $response->json('tags'); 157 | } 158 | 159 | public function getArticle($articleId): ArticleResource 160 | { 161 | return $this->getResource('articles', $articleId); 162 | } 163 | 164 | public function updateArticle($articleId, $data): ArticleResource 165 | { 166 | return $this->updateResource('articles', $articleId, $data); 167 | } 168 | 169 | public function deleteArticle($articleId): void 170 | { 171 | $this->deleteResource('articles', $articleId); 172 | } 173 | 174 | public function getAssets($themeId, array $params = []): Collection 175 | { 176 | return $this->getResources('assets', $params, ['themes', $themeId]); 177 | } 178 | 179 | public function getAsset($themeId, $assetKey): AssetResource 180 | { 181 | $response = $this->get('themes/'.$themeId.'/assets.json?asset[key]='.$assetKey); 182 | 183 | return new AssetResource($response['asset'], $this); 184 | } 185 | 186 | public function updateAsset($themeId, array $data) 187 | { 188 | $response = $this->put('themes/'.$themeId.'/assets.json', $data); 189 | 190 | return new AssetResource($response['asset'], $this); 191 | } 192 | 193 | public function deleteAsset($themeId, $assetKey) 194 | { 195 | $this->delete('themes/'.$themeId.'/assets.json?asset[key]='.$assetKey); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesOrders.php: -------------------------------------------------------------------------------- 1 | createResource('orders', $data); 21 | } 22 | 23 | public function getOrdersCount(array $params = []): int 24 | { 25 | return $this->getResourceCount('orders', $params); 26 | } 27 | 28 | public function paginateOrders(array $params = []): Cursor 29 | { 30 | return $this->cursor($this->getOrders($params)); 31 | } 32 | 33 | public function getOrders(array $params = []): Collection 34 | { 35 | return $this->getResources('orders', $params); 36 | } 37 | 38 | public function getOrder($orderId): OrderResource 39 | { 40 | return $this->getResource('orders', $orderId); 41 | } 42 | 43 | public function updateOrder($orderId, $data): OrderResource 44 | { 45 | return $this->updateResource('orders', $orderId, $data); 46 | } 47 | 48 | public function deleteOrder($orderId): void 49 | { 50 | $this->deleteResource('orders', $orderId); 51 | } 52 | 53 | public function closeOrder($orderId): OrderResource 54 | { 55 | $response = $this->post("orders/{$orderId}/close.json"); 56 | 57 | return new OrderResource($response['order'], $this); 58 | } 59 | 60 | public function openOrder($orderId): OrderResource 61 | { 62 | $response = $this->post("orders/{$orderId}/open.json"); 63 | 64 | return new OrderResource($response['order'], $this); 65 | } 66 | 67 | public function cancelOrder($orderId): OrderResource 68 | { 69 | $response = $this->post("orders/{$orderId}/cancel.json"); 70 | 71 | return new OrderResource($response['order'], $this); 72 | } 73 | 74 | public function createOrderRisk($orderId, array $data): RiskResource 75 | { 76 | return $this->createResource('risks', $data, ['orders', $orderId]); 77 | } 78 | 79 | public function getOrderRisks($orderId, array $params = []): Collection 80 | { 81 | return $this->getResources('risks', $params, ['orders', $orderId]); 82 | } 83 | 84 | public function getOrderRisk($orderId, $riskId): Collection 85 | { 86 | return $this->getResource('risks', $riskId, ['orders', $orderId]); 87 | } 88 | 89 | public function updateOrderRisk($orderId, $riskId, array $data): RiskResource 90 | { 91 | return $this->updateResource('risks', $riskId, $data, ['orders', $orderId]); 92 | } 93 | 94 | public function deleteOrderRisk($orderId, $riskId): void 95 | { 96 | $this->deleteResource('risks', $riskId, ['orders', $orderId]); 97 | } 98 | 99 | public function createOrderRefund($orderId, array $data): RefundResource 100 | { 101 | return $this->createResource('refunds', $data, ['orders', $orderId]); 102 | } 103 | 104 | public function getOrderRefunds($orderId, array $params = []): Collection 105 | { 106 | return $this->getResources('refunds', $params, ['orders', $orderId]); 107 | } 108 | 109 | public function getOrderRefund($orderId, $refundId): RefundResource 110 | { 111 | return $this->getResource('refunds', $refundId, ['orders', $orderId]); 112 | } 113 | 114 | public function calculateOrderRefund($orderId, array $data): RefundResource 115 | { 116 | $response = $this->post("orders/{$orderId}/refunds/calculate.json", ['refund' => $data]); 117 | 118 | return new RefundResource($response['refund'], $this); 119 | } 120 | 121 | public function getOrderTransactionsCount($orderId, array $params = []): Collection 122 | { 123 | return $this->getResourceCount('transactions', $params, ['orders', $orderId]); 124 | } 125 | 126 | public function getOrderTransactions($orderId, array $params = []): Collection 127 | { 128 | return $this->getResources('transactions', $params, ['orders', $orderId]); 129 | } 130 | 131 | public function createOrderTransaction($orderId, array $data): TransactionResource 132 | { 133 | return $this->createResource('transactions', $data, ['orders', $orderId]); 134 | } 135 | 136 | public function createDraftOrder(array $data): DraftOrderResource 137 | { 138 | return $this->createResource('draft_orders', $data); 139 | } 140 | 141 | public function getDraftOrdersCount(array $params = []): int 142 | { 143 | return $this->getResourceCount('draft_orders', $params); 144 | } 145 | 146 | public function paginateDraftOrders(array $params = []): Cursor 147 | { 148 | return $this->cursor($this->getDraftOrders($params)); 149 | } 150 | 151 | public function getDraftOrders(array $params = []): Collection 152 | { 153 | return $this->getResources('draft_orders', $params); 154 | } 155 | 156 | public function getDraftOrder($orderId): DraftOrderResource 157 | { 158 | return $this->getResource('draft_orders', $orderId); 159 | } 160 | 161 | public function updateDraftOrder($orderId, $data): DraftOrderResource 162 | { 163 | return $this->updateResource('draft_orders', $orderId, $data); 164 | } 165 | 166 | public function deleteDraftOrder($orderId): void 167 | { 168 | $this->deleteResource('draft_orders', $orderId); 169 | } 170 | 171 | public function sendDraftOrderInvoice($orderId, array $data): ApiResource 172 | { 173 | $response = $this->post("draft_orders/{$orderId}/send_invoice.json", ['draft_order_invoice' => $data]); 174 | 175 | return new ApiResource($response['draft_order_invoice'], $this); 176 | } 177 | 178 | public function completeDraftOrder($orderId, bool $paymentPending = false): DraftOrderResource 179 | { 180 | $response = $this->put("draft_orders/{$orderId}/complete.json", ['payment_pending' => $paymentPending]); 181 | 182 | return new DraftOrderResource($response['draft_order'], $this); 183 | } 184 | 185 | public function getCheckoutsCount(array $params = []): int 186 | { 187 | return $this->getResourceCount('checkouts', $params); 188 | } 189 | 190 | public function getCheckouts(array $params = []): Collection 191 | { 192 | return $this->getResources('checkouts', $params); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesPlus.php: -------------------------------------------------------------------------------- 1 | createResource('products', $data); 18 | } 19 | 20 | public function getProductsCount(array $params = []): int 21 | { 22 | return $this->getResourceCount('products', $params); 23 | } 24 | 25 | public function paginateProducts(array $params = []): Cursor 26 | { 27 | return $this->cursor($this->getProducts($params)); 28 | } 29 | 30 | public function getProducts(array $params = []): Collection 31 | { 32 | return $this->getResources('products', $params); 33 | } 34 | 35 | public function getProduct($productId): ProductResource 36 | { 37 | return $this->getResource('products', $productId); 38 | } 39 | 40 | public function updateProduct($productId, $data): ProductResource 41 | { 42 | return $this->updateResource('products', $productId, $data); 43 | } 44 | 45 | public function deleteProduct($productId): void 46 | { 47 | $this->deleteResource('products', $productId); 48 | } 49 | 50 | public function createVariant($productId, array $data): VariantResource 51 | { 52 | return $this->createResource('variants', $data, ['products', $productId]); 53 | } 54 | 55 | public function getVariantsCount($productId, array $params = []): int 56 | { 57 | return $this->getResourceCount('variants', $params, ['products', $productId]); 58 | } 59 | 60 | public function paginateVariants($productId, array $params = []): Cursor 61 | { 62 | return $this->cursor($this->getVariants($productId, $params)); 63 | } 64 | 65 | public function getVariants($productId, array $params = []): Collection 66 | { 67 | return $this->getResources('variants', $params, ['products', $productId]); 68 | } 69 | 70 | public function getVariant($variantId): VariantResource 71 | { 72 | return $this->getResource('variants', $variantId); 73 | } 74 | 75 | public function updateVariant($variantId, array $data): VariantResource 76 | { 77 | return $this->updateResource('variants', $variantId, $data); 78 | } 79 | 80 | public function deleteVariant($productId, $variantId): void 81 | { 82 | $this->deleteResource('variants', $variantId, ['products', $productId]); 83 | } 84 | 85 | public function createProductImage($productId, array $data): ImageResource 86 | { 87 | return $this->createResource('images', $data, ['products', $productId]); 88 | } 89 | 90 | public function getProductImagesCount($productId, array $params = []): int 91 | { 92 | return $this->getResourceCount('images', $params, ['products', $productId]); 93 | } 94 | 95 | public function paginateProductImages($productId, array $params = []): Cursor 96 | { 97 | return $this->cursor($this->getProductImages($productId, $params)); 98 | } 99 | 100 | public function getProductImages($productId, array $params = []): Collection 101 | { 102 | return $this->getResources('images', $params, ['products', $productId]); 103 | } 104 | 105 | public function getProductImage($productId, $imageId): ImageResource 106 | { 107 | return $this->getResource('images', $imageId, ['products', $productId]); 108 | } 109 | 110 | public function updateProductImage($productId, $imageId, array $data): ImageResource 111 | { 112 | return $this->updateResource('images', $imageId, $data, ['products', $productId]); 113 | } 114 | 115 | public function deleteProductImage($productId, $imageId): void 116 | { 117 | $this->deleteResource('images', $imageId, ['products', $productId]); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesSalesChannel.php: -------------------------------------------------------------------------------- 1 | get('shopify_payments/balance.json'); 17 | 18 | return new BalanceResource($response['balance'], $this); 19 | } 20 | 21 | public function getShopifyPaymentsDisputes(array $params = []): Collection 22 | { 23 | return $this->getResources('disputes', $params, ['shopify_payments']); 24 | } 25 | 26 | public function getShopifyPaymentsDispute($disputeId): DisputeResource 27 | { 28 | return $this->getResource('disputes', $disputeId, ['shopify_payments']); 29 | } 30 | 31 | public function getShopifyPaymentsPayouts(array $params = []): Collection 32 | { 33 | return $this->getResources('payouts', $params, ['shopify_payments']); 34 | } 35 | 36 | public function getShopifyPaymentsPayout($payoutId): PayoutResource 37 | { 38 | return $this->getResource('payouts', $payoutId, ['shopify_payments']); 39 | } 40 | 41 | public function getShopifyPaymentsBalanceTransactions(array $params = []): Collection 42 | { 43 | return $this->getResources('transactions', $params, ['shopify_payments', 'balance']); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/REST/Actions/ManagesStoreProperties.php: -------------------------------------------------------------------------------- 1 | createResource('countries', $data); 17 | } 18 | 19 | public function getCountriesCount(array $params = []): int 20 | { 21 | return $this->getResourceCount('countries', $params); 22 | } 23 | 24 | public function getCountries(array $params = []): Collection 25 | { 26 | return $this->getResources('countries', $params); 27 | } 28 | 29 | public function getCountry($countryId): CountryResource 30 | { 31 | return $this->getResource('countries', $countryId); 32 | } 33 | 34 | public function updateCountry($countryId, array $data): CountryResource 35 | { 36 | return $this->updateResource('countries', $countryId, $data); 37 | } 38 | 39 | public function deleteCountry($countryId): void 40 | { 41 | $this->deleteResource('countries', $countryId); 42 | } 43 | 44 | public function paginateCurrencies(array $params = []): Cursor 45 | { 46 | return $this->cursor($this->getCurrencies($params)); 47 | } 48 | 49 | public function getCurrencies(array $params = []): Collection 50 | { 51 | return $this->getResources('currencies', $params); 52 | } 53 | 54 | public function getPolicies(array $params = []): Collection 55 | { 56 | return $this->getResources('policies', $params); 57 | } 58 | 59 | public function getCountryProvincesCount($countryId, array $params = []): int 60 | { 61 | return $this->getResourceCount('provinces', $params, ['countries', $countryId]); 62 | } 63 | 64 | public function getCountryProvinces($countryId, array $params = []): Collection 65 | { 66 | return $this->getResources('provinces', $params, ['countries', $countryId]); 67 | } 68 | 69 | public function getCountryProvince($countryId, $provinceId): CountryResource 70 | { 71 | return $this->getResource('provinces', $provinceId, ['countries', $countryId]); 72 | } 73 | 74 | public function updateCountryProvince($countryId, $provinceId, array $data): CountryResource 75 | { 76 | return $this->updateResource('provinces', $provinceId, $data, ['countries', $countryId]); 77 | } 78 | 79 | public function getShippingZones(array $params = []): Collection 80 | { 81 | return $this->getResources('shipping_zones', $params); 82 | } 83 | 84 | public function shop(): ApiResource 85 | { 86 | $response = $this->get('shop.json'); 87 | 88 | return new ApiResource($response->json('shop'), $this); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/REST/Cursor.php: -------------------------------------------------------------------------------- 1 | ; rel="?{type}"?/i'; 15 | 16 | protected Shopify $shopify; 17 | protected int $position = 0; 18 | protected array $links = []; 19 | protected array $results = []; 20 | protected string $resourceClass; 21 | 22 | public function __construct(Shopify $shopify, Collection $results) 23 | { 24 | $this->shopify = $shopify; 25 | $this->results[$this->position] = $results; 26 | 27 | $this->detectResourceClass(); 28 | $this->extractLinks(); 29 | } 30 | 31 | public function current(): Collection 32 | { 33 | return $this->results[$this->position]; 34 | } 35 | 36 | public function hasNext(): bool 37 | { 38 | return ! empty($this->links['next']); 39 | } 40 | 41 | public function hasPrev(): bool 42 | { 43 | return $this->position > 0; 44 | } 45 | 46 | public function key(): int 47 | { 48 | return $this->position; 49 | } 50 | 51 | public function next(): void 52 | { 53 | $this->position++; 54 | 55 | if (! $this->valid() && $this->hasNext()) { 56 | $this->results[$this->position] = $this->fetchNextResults(); 57 | $this->extractLinks(); 58 | } 59 | } 60 | 61 | public function prev(): void 62 | { 63 | if (! $this->hasPrev()) { 64 | throw new RuntimeException('No previous results available.'); 65 | } 66 | 67 | $this->position--; 68 | } 69 | 70 | public function rewind(): void 71 | { 72 | $this->position = 0; 73 | } 74 | 75 | public function valid(): bool 76 | { 77 | return isset($this->results[$this->position]); 78 | } 79 | 80 | protected function extractLinks(): void 81 | { 82 | $response = $this->shopify->getLastResponse(); 83 | 84 | if (! $response->header('Link')) { 85 | $this->links = []; 86 | 87 | return; 88 | } 89 | 90 | $links = [ 91 | 'next' => null, 92 | 'previous' => null, 93 | ]; 94 | 95 | foreach (array_keys($links) as $type) { 96 | $matched = preg_match( 97 | str_replace('{type}', $type, static::LINK_REGEX), 98 | $response->header('Link'), 99 | $matches 100 | ); 101 | 102 | if ($matched) { 103 | $links[$type] = $matches[1]; 104 | } 105 | } 106 | 107 | $this->links = $links; 108 | } 109 | 110 | protected function fetchNextResults(): Collection 111 | { 112 | $response = $this->shopify->get( 113 | Str::after($this->links['next'], $this->shopify->getBaseUrl()) 114 | ); 115 | 116 | return Collection::make(Arr::first($response->json())) 117 | ->map(fn ($attr) => new $this->resourceClass($attr, $this->shopify)); 118 | } 119 | 120 | private function detectResourceClass() 121 | { 122 | if ($resource = optional($this->results[0])->first()) { 123 | $this->resourceClass = get_class($resource); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/REST/Resources/ApiResource.php: -------------------------------------------------------------------------------- 1 | attributes = $attributes; 23 | $this->shopify = $shopify; 24 | } 25 | 26 | /** 27 | * Get all of the attributes except for a specified array of keys. 28 | * 29 | * @param array|string $keys 30 | * @return array 31 | */ 32 | public function except($keys): array 33 | { 34 | return Arr::except($this->getAttributes(), is_array($keys) ? $keys : func_get_args()); 35 | } 36 | 37 | /** 38 | * Get a subset of the attributes. 39 | * 40 | * @param array|string $keys 41 | * @return array 42 | */ 43 | public function only($keys): array 44 | { 45 | return Arr::only($this->getAttributes(), is_array($keys) ? $keys : func_get_args()); 46 | } 47 | 48 | /** 49 | * @param string $key 50 | * @return mixed 51 | */ 52 | public function __get($key) 53 | { 54 | if (array_key_exists($key, $this->attributes)) { 55 | return $this->getAttribute($key); 56 | } 57 | 58 | throw new Exception('Property '.$key.' does not exist on '.get_called_class()); 59 | } 60 | 61 | /** 62 | * @param string $key 63 | * @return bool 64 | */ 65 | public function __isset($key): bool 66 | { 67 | return array_key_exists($key, $this->attributes); 68 | } 69 | 70 | /** 71 | * Determine if the given attribute exists. 72 | * 73 | * @param mixed $offset 74 | * @return bool 75 | */ 76 | #[\ReturnTypeWillChange] 77 | public function offsetExists($offset) 78 | { 79 | return array_key_exists($offset, $this->attributes); 80 | } 81 | 82 | /** 83 | * Get the value for a given offset. 84 | * 85 | * @param mixed $offset 86 | * @return mixed 87 | */ 88 | #[\ReturnTypeWillChange] 89 | public function offsetGet($offset) 90 | { 91 | return $this->getAttribute($offset); 92 | } 93 | 94 | /** 95 | * Set the value for a given offset. 96 | * 97 | * @param mixed $offset 98 | * @param mixed $value 99 | * @return void 100 | */ 101 | #[\ReturnTypeWillChange] 102 | public function offsetSet($offset, $value) 103 | { 104 | return $this->setAttribute($offset, $value); 105 | } 106 | 107 | /** 108 | * Unset the value for a given offset. 109 | * 110 | * @param mixed $offset 111 | * @return void 112 | */ 113 | #[\ReturnTypeWillChange] 114 | public function offsetUnset($offset) 115 | { 116 | unset($this->attributes[$offset]); 117 | } 118 | 119 | /** 120 | * Get an attribute. 121 | * 122 | * @param string $key 123 | * @return mixed 124 | */ 125 | protected function getAttribute($key) 126 | { 127 | return $this->attributes[$key]; 128 | } 129 | 130 | /** 131 | * Set an attribute. 132 | * 133 | * @param string $key 134 | * @param mixed $value 135 | */ 136 | protected function setAttribute($key, $value) 137 | { 138 | $this->attributes[$key] = $value; 139 | 140 | return $this; 141 | } 142 | 143 | /** 144 | * Get attributes for the resource. 145 | * 146 | * @return array 147 | */ 148 | public function getAttributes() 149 | { 150 | return $this->attributes; 151 | } 152 | 153 | public function toArray() 154 | { 155 | return $this->getAttributes(); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/REST/Resources/ArticleResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateArticle($this->id, $data); 10 | } 11 | 12 | public function publish(): self 13 | { 14 | return $this->update(['published' => true]); 15 | } 16 | 17 | public function unpublish(): self 18 | { 19 | return $this->update(['published' => false]); 20 | } 21 | 22 | public function delete(): void 23 | { 24 | $this->shopify->deleteArticle($this->id); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/REST/Resources/AssetResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateBlog($this->id, $data); 10 | } 11 | 12 | public function delete(): void 13 | { 14 | $this->shopify->deleteBlog($this->id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/REST/Resources/CollectResource.php: -------------------------------------------------------------------------------- 1 | shopify->deleteCollect($this->id); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/REST/Resources/CountryResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateCustomCollection($this->id, $data); 12 | } 13 | 14 | public function delete(): void 15 | { 16 | $this->shopify->deleteCustomCollection($this->id); 17 | } 18 | 19 | public function getProducts(array $params = []): Collection 20 | { 21 | return $this->shopify->getCollectionProducts($this->id, $params); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/REST/Resources/CustomerResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateCustomer($this->id, $data); 12 | } 13 | 14 | public function delete(): void 15 | { 16 | $this->shopify->deleteCustomer($this->id); 17 | } 18 | 19 | public function getAddresses(array $params = []): Collection 20 | { 21 | return $this->shopify->getCustomerAddresses($this->id, $params); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/REST/Resources/DisputeResource.php: -------------------------------------------------------------------------------- 1 | shopify->deleteProductImage($this->product_id, $this->id); 10 | } 11 | 12 | public function update(array $data): self 13 | { 14 | return $this->shopify->updateProductImage($this->product_id, $this->id, $data); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/REST/Resources/MetafieldResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateMetafield($this->id, $data); 10 | } 11 | 12 | public function delete(): void 13 | { 14 | $this->shopify->deleteMetafield($this->id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/REST/Resources/OrderResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateOrder($this->id, $data); 12 | } 13 | 14 | public function delete(): void 15 | { 16 | $this->shopify->deleteOrder($this->id); 17 | } 18 | 19 | public function cancel(): ApiResource 20 | { 21 | return $this->shopify->cancelOrder($this->id); 22 | } 23 | 24 | public function close(): ApiResource 25 | { 26 | return $this->shopify->closeOrder($this->id); 27 | } 28 | 29 | public function open(): ApiResource 30 | { 31 | return $this->shopify->openOrder($this->id); 32 | } 33 | 34 | public function getFulfillments(array $params = []): Collection 35 | { 36 | return $this->shopify->getOrderFulfillments($this->id, $params); 37 | } 38 | 39 | public function getRefunds(array $params = []): Collection 40 | { 41 | return $this->shopify->getOrderRefunds($this->id, $params); 42 | } 43 | 44 | public function getRisks(array $params = []): Collection 45 | { 46 | return $this->shopify->getOrderRisks($this->id, $params); 47 | } 48 | 49 | public function getTransactions(array $params = []): Collection 50 | { 51 | return $this->shopify->getOrderTransactions($this->id, $params); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/REST/Resources/PageResource.php: -------------------------------------------------------------------------------- 1 | shopify->updatePage($this->id, $data); 10 | } 11 | 12 | public function delete(): void 13 | { 14 | $this->shopify->deletePage($this->id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/REST/Resources/PayoutResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateProduct($this->id, $data); 12 | } 13 | 14 | public function delete(): void 15 | { 16 | $this->shopify->deleteProduct($this->id); 17 | } 18 | 19 | public function publish(): self 20 | { 21 | return $this->update(['published' => true]); 22 | } 23 | 24 | public function unpublish(): self 25 | { 26 | return $this->update(['published' => false]); 27 | } 28 | 29 | public function getImages(array $params = []): Collection 30 | { 31 | return $this->shopify->getProductImages($this->id, $params); 32 | } 33 | 34 | public function getMetafields(array $params = []): Collection 35 | { 36 | return $this->shopify->getProductMetafields($this->id, $params); 37 | } 38 | 39 | public function getVariants(array $params = []): Collection 40 | { 41 | return $this->shopify->getVariants($this->id, $params); 42 | } 43 | 44 | public function images(): Collection 45 | { 46 | return Collection::make($this->images) 47 | ->map(fn ($attributes) => new ImageResource($attributes, $this->shopify)); 48 | } 49 | 50 | public function variants(): Collection 51 | { 52 | return Collection::make($this->variants) 53 | ->map(fn ($attributes) => new VariantResource($attributes, $this->shopify)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/REST/Resources/RefundResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateSmartCollection($this->id, $data); 12 | } 13 | 14 | public function delete(): void 15 | { 16 | $this->shopify->deleteSmartCollection($this->id); 17 | } 18 | 19 | public function getProducts(array $params = []): Collection 20 | { 21 | return $this->shopify->getCollectionProducts($this->id, $params); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/REST/Resources/TransactionResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateVariant($this->id, $data); 10 | } 11 | 12 | public function delete(): void 13 | { 14 | $this->shopify->deleteVariant($this->product_id, $this->id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/REST/Resources/WebhookResource.php: -------------------------------------------------------------------------------- 1 | shopify->updateWebhook($this->id, $data); 10 | } 11 | 12 | public function delete(): void 13 | { 14 | $this->shopify->deleteWebhook($this->id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Shopify.php: -------------------------------------------------------------------------------- 1 | withCredentials($accessToken, $domain, $apiVersion); 62 | } 63 | 64 | public function cursor(Collection $results): Cursor 65 | { 66 | return new Cursor($this, $results); 67 | } 68 | 69 | public function getHttpClient(): PendingRequest 70 | { 71 | return $this->httpClient ??= Http::baseUrl($this->getBaseUrl()) 72 | ->withHeaders(['X-Shopify-Access-Token' => $this->accessToken]); 73 | } 74 | 75 | public function graphQl(): PendingRequest 76 | { 77 | return Http::baseUrl("https://{$this->domain}/admin/api/{$this->apiVersion}/graphql.json") 78 | ->withHeaders([ 79 | 'X-Shopify-Access-Token' => $this->accessToken, 80 | 'Content-Type' => 'application/json', 81 | ]); 82 | } 83 | 84 | public function getBaseUrl(): string 85 | { 86 | return "https://{$this->domain}/admin/api/{$this->apiVersion}"; 87 | } 88 | 89 | public function tap(callable $callback): self 90 | { 91 | $callback($this->getHttpClient()); 92 | 93 | return $this; 94 | } 95 | 96 | public function withCredentials(string $accessToken, string $domain, string $apiVersion): self 97 | { 98 | $this->accessToken = $accessToken; 99 | $this->domain = $domain; 100 | $this->apiVersion = $apiVersion; 101 | 102 | $this->httpClient = null; 103 | 104 | return $this; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/ShopifyServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishConfig(); 20 | $this->registerMacros(); 21 | } 22 | 23 | public function register() 24 | { 25 | $this->app->singleton(Shopify::class, fn () => Factory::fromConfig()); 26 | 27 | $this->app->alias(Shopify::class, 'shopify'); 28 | 29 | $this->app->bind(ErrorHandlerInterface::class, Handler::class); 30 | 31 | $this->app->singleton(SecretProvider::class, function (Application $app) { 32 | $secretProvider = config('shopify.webhooks.secret_provider'); 33 | 34 | return $app->make($secretProvider); 35 | }); 36 | } 37 | 38 | protected function publishConfig() 39 | { 40 | if ($this->app->runningInConsole()) { 41 | $this->publishes([ 42 | __DIR__.'/../config/shopify.php' => config_path('shopify.php'), 43 | ], 'laravel-shopify'); 44 | } 45 | 46 | $this->mergeConfigFrom(__DIR__.'/../config/shopify.php', 'shopify'); 47 | } 48 | 49 | protected function registerMacros(): void 50 | { 51 | Route::macro('shopifyWebhooks', function (string $uri = 'shopify/webhooks') { 52 | return $this->post($uri, [WebhookController::class, 'handle'])->name('shopify.webhooks'); 53 | }); 54 | 55 | Request::macro('shopifyShopDomain', fn () => $this->header(Webhook::HEADER_SHOP_DOMAIN)); 56 | 57 | Request::macro('shopifyHmacSignature', fn () => $this->header(Webhook::HEADER_HMAC_SIGNATURE)); 58 | 59 | Request::macro('shopifyTopic', fn () => $this->header(Webhook::HEADER_TOPIC)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Support/Facades/Shopify.php: -------------------------------------------------------------------------------- 1 | getHttpClient()->get($url, $query); 22 | 23 | $this->handleErrorResponse($response); 24 | 25 | return $response; 26 | } 27 | 28 | public function post(string $url, array $data = []): Response 29 | { 30 | $response = $this->getHttpClient()->post($url, $data); 31 | 32 | $this->handleErrorResponse($response); 33 | 34 | return $response; 35 | } 36 | 37 | public function put(string $url, array $data = []): Response 38 | { 39 | $response = $this->getHttpClient()->put($url, $data); 40 | 41 | $this->handleErrorResponse($response); 42 | 43 | return $response; 44 | } 45 | 46 | public function delete(string $url, array $data = []): Response 47 | { 48 | $response = $this->getHttpClient()->delete($url, $data); 49 | 50 | $this->handleErrorResponse($response); 51 | 52 | return $response; 53 | } 54 | 55 | protected function resourceClassFor(string $resource): string 56 | { 57 | $resourceClass = Str::of($resource) 58 | ->studly() 59 | ->singular() 60 | ->prepend('Signifly\\Shopify\\REST\\Resources\\') 61 | ->append('Resource'); 62 | 63 | return class_exists($resourceClass) ? $resourceClass : ApiResource::class; 64 | } 65 | 66 | protected function createResource(string $resource, array $data, array $uriPrefix = [], string $responseKey = null): ApiResource 67 | { 68 | $key = Str::singular($resource); 69 | $resourceClass = $this->resourceClassFor($resource); 70 | 71 | $response = $this->post(implode('/', [...$uriPrefix, "{$resource}.json"]), [$key => $data]); 72 | 73 | if (! empty($responseKey)) { 74 | $key = $responseKey; 75 | } 76 | 77 | return new $resourceClass($response[$key], $this); 78 | } 79 | 80 | protected function getResourceCount(string $resource, array $params, array $uriPrefix = []): int 81 | { 82 | $response = $this->get(implode('/', [...$uriPrefix, "{$resource}/count.json"]), $params); 83 | 84 | return $response['count'] ?? 0; 85 | } 86 | 87 | protected function getResources(string $resource, array $params, array $uriPrefix = []): Collection 88 | { 89 | $resourceClass = $this->resourceClassFor($resource); 90 | $response = $this->get(implode('/', [...$uriPrefix, "{$resource}.json"]), $params); 91 | 92 | return $this->transformCollection($response[$resource], $resourceClass); 93 | } 94 | 95 | protected function getResource(string $resource, $resourceId, array $uriPrefix = []): ApiResource 96 | { 97 | $key = Str::singular($resource); 98 | $resourceClass = $this->resourceClassFor($resource); 99 | 100 | $response = $this->get(implode('/', [...$uriPrefix, "{$resource}/{$resourceId}.json"])); 101 | 102 | return new $resourceClass($response[$key], $this); 103 | } 104 | 105 | protected function updateResource(string $resource, $resourceId, array $data, array $uriPrefix = [], string $responseKey = null): ApiResource 106 | { 107 | $key = Str::singular($resource); 108 | $resourceClass = $this->resourceClassFor($resource); 109 | 110 | $response = $this->put(implode('/', [...$uriPrefix, "{$resource}/{$resourceId}.json"]), [$key => $data]); 111 | 112 | if (! empty($responseKey)) { 113 | $key = $responseKey; 114 | } 115 | 116 | return new $resourceClass($response[$key], $this); 117 | } 118 | 119 | protected function deleteResource(string $resource, $resourceId, array $uriPrefix = []): void 120 | { 121 | $this->delete(implode('/', [...$uriPrefix, "{$resource}/{$resourceId}.json"])); 122 | } 123 | 124 | public function getLastResponse(): Response 125 | { 126 | return $this->lastResponse; 127 | } 128 | 129 | private function handleErrorResponse(Response $response): void 130 | { 131 | $this->lastResponse = $response; 132 | 133 | app(ErrorHandlerInterface::class)->handle($response); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Support/TransformsResources.php: -------------------------------------------------------------------------------- 1 | map(function ($attributes) use ($class) { 13 | return $this->transformItem($attributes, $class); 14 | }); 15 | } 16 | 17 | protected function transformItem(array $attributes, string $class): ApiResource 18 | { 19 | return new $class($attributes, $this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Support/VerifiesWebhooks.php: -------------------------------------------------------------------------------- 1 | calculateSignature($data, $secret)); 10 | } 11 | 12 | public function calculateSignature(string $data, string $secret): string 13 | { 14 | return base64_encode(hash_hmac('sha256', $data, $secret, true)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Webhooks/ConfigSecretProvider.php: -------------------------------------------------------------------------------- 1 | domain = $domain; 20 | $this->topic = $topic; 21 | $this->payload = $payload; 22 | } 23 | 24 | public function domain(): string 25 | { 26 | return $this->domain; 27 | } 28 | 29 | public function eventName(): string 30 | { 31 | return 'shopify-webhooks.'.str_replace('/', '-', $this->topic()); 32 | } 33 | 34 | public function payload(): array 35 | { 36 | return $this->payload; 37 | } 38 | 39 | public function topic(): string 40 | { 41 | return $this->topic; 42 | } 43 | 44 | public static function fromRequest(Request $request): self 45 | { 46 | return new self( 47 | $request->shopifyShopDomain(), 48 | $request->shopifyTopic(), 49 | json_decode($request->getContent(), true) 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Webhooks/WebhookValidator.php: -------------------------------------------------------------------------------- 1 | secretProvider = $secretProvider; 18 | } 19 | 20 | public function validate(string $signature, string $domain, string $data): void 21 | { 22 | // Validate webhook secret presence 23 | $secret = $this->secretProvider->getSecret($domain); 24 | throw_if(empty($secret), WebhookFailed::missingSigningSecret()); 25 | 26 | // Validate webhook signature 27 | throw_unless( 28 | $this->isWebhookSignatureValid($signature, $data, $secret), 29 | WebhookFailed::invalidSignature($signature) 30 | ); 31 | } 32 | 33 | public function validateFromRequest(Request $request): void 34 | { 35 | // Validate signature presence 36 | $signature = $request->shopifyHmacSignature(); 37 | throw_unless($signature, WebhookFailed::missingSignature()); 38 | 39 | // Validate topic presence 40 | throw_unless($request->shopifyTopic(), WebhookFailed::missingTopic()); 41 | 42 | $this->validate($signature, $request->shopifyShopDomain(), $request->getContent()); 43 | } 44 | } 45 | --------------------------------------------------------------------------------