├── .coveralls.yml ├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.xml ├── composer.json ├── phpmd.xml ├── phpunit.xml ├── src └── Magento │ └── Client │ ├── Rest │ ├── AccessToken.php │ ├── MagentoOauthPlugin.php │ ├── MagentoRestClient.php │ ├── OauthException.php │ ├── RequestToken.php │ └── Token.php │ └── Xmlrpc │ └── MagentoXmlrpcClient.php └── test └── bootstrap.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | # for php-coveralls 2 | service_name: travis-ci 3 | src_dir: src 4 | coverage_clover: build/logs/clover.xml 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; top-most EditorConfig file 2 | root = true 3 | 4 | ; Unix-style newlines 5 | [*] 6 | end_of_line = LF 7 | 8 | [*.php] 9 | indent_style = space 10 | indent_size = 4 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /composer.lock 3 | /vendor 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - "5.5" 5 | - "5.4" 6 | - "5.3" 7 | 8 | before_script: 9 | - composer install --prefer-dist --dev 10 | 11 | after_script: 12 | - php vendor/bin/coveralls -v 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Chris Pliakas 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Magento Client Library For PHP 2 | 3 | [![Build Status](https://travis-ci.org/cpliakas/magento-client-php.png)](https://travis-ci.org/cpliakas/magento-client-php) 4 | [![Coverage Status](https://coveralls.io/repos/cpliakas/magento-client-php/badge.png?branch=master)](https://coveralls.io/r/cpliakas/magento-client-php?branch=master) 5 | [![Total Downloads](https://poser.pugx.org/cpliakas/magento-client-php/downloads.png)](https://packagist.org/packages/cpliakas/magento-client-php) 6 | [![Latest Stable Version](https://poser.pugx.org/cpliakas/magento-client-php/v/stable.png)](https://packagist.org/packages/cpliakas/magento-client-php) 7 | 8 | Provides a client library to make REST and XMLRPC calls to a Magento instance. 9 | 10 | ## Installation 11 | 12 | Magento Client Library For PHP can be installed with [Composer](http://getcomposer.org) 13 | by adding it as a dependency to your project's composer.json file. 14 | 15 | ```json 16 | { 17 | "require": { 18 | "cpliakas/magento-client-php": "*" 19 | } 20 | } 21 | ``` 22 | 23 | After running `php composer.phar update` on the command line, include the 24 | autoloader in your PHP scripts so that the SDK classes are made available. 25 | 26 | ```php 27 | require_once 'vendor/autoload.php'; 28 | ``` 29 | 30 | Please refer to [Composer's documentation](https://github.com/composer/composer/blob/master/doc/00-intro.md#introduction) 31 | for more detailed installation and usage instructions. 32 | 33 | ## Usage 34 | 35 | ### XMLRPC 36 | 37 | The following example returns a list of products with SKUs that start with "123": 38 | 39 | ```php 40 | 41 | use Magento\Client\Xmlrpc\MagentoXmlrpcClient; 42 | 43 | $client = MagentoXmlrpcClient::factory(array( 44 | 'base_url' => 'http://magentohost', 45 | 'api_user' => 'api.user', 46 | 'api_key' => 'some.private.key', 47 | )); 48 | 49 | $filters = array( 50 | 'sku' => array('like' => '123%'), 51 | ); 52 | 53 | $result = $client->call('catalog_product.list', array($filters)); 54 | ``` 55 | 56 | ### Rest 57 | 58 | The following example returns a list of products: 59 | 60 | ```php 61 | 62 | use Magento\Client\Rest\MagentoRestClient; 63 | 64 | $client = MagentoRestClient::factory(array( 65 | 'base_url' => 'http://magentohost', 66 | 'consumer_key' => 'abc123...', 67 | 'consumer_secret' => 'def456...', 68 | 'token' => 'ghi789...', 69 | 'token_secret' => 'jkl012...', 70 | )); 71 | 72 | $result = $client->get('/api/rest/products')->send()->json(); 73 | 74 | ``` 75 | 76 | Refer to [Guzzle's documentation](https://guzzle.readthedocs.org/en/latest/http-client/request.html#creating-requests-with-a-client) 77 | for more information on sending requests to the server. 78 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cpliakas/magento-client-php", 3 | "type": "library", 4 | "description": "A PHP client library that consumes Magento's REST and XMLRPC APIs", 5 | "homepage": "https://github.com/cpliakas/magento-client-php", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "See contributors", 10 | "homepage": "https://github.com/cpliakas/magento-client-php/graphs/contributors" 11 | } 12 | ], 13 | "support": { 14 | "issues": "https://github.com/cpliakas/magento-client-php/issues" 15 | }, 16 | "require": { 17 | "php": ">=5.3.3", 18 | "guzzle/guzzle": "~3.0", 19 | "lstrojny/fxmlrpc": ">=0.8,<0.9" 20 | }, 21 | "require-dev": { 22 | "pdepend/pdepend": "~1.0", 23 | "phploc/phploc": "~2.0", 24 | "phpmd/phpmd": "~1.0", 25 | "phpunit/phpunit": "~3.0", 26 | "satooshi/php-coveralls": "*", 27 | "sebastian/phpcpd": "~2.0" 28 | }, 29 | "autoload": { 30 | "psr-0": { 31 | "Magento\\Client": "src/" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /phpmd.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | PHP Project Starter Rulset: Adopted From Jenkins for Symfony 2 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | test 15 | 16 | 17 | 18 | 19 | 20 | src 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Magento/Client/Rest/AccessToken.php: -------------------------------------------------------------------------------- 1 | getParamsToSign($request, $timestamp, $nonce); 23 | 24 | // Convert booleans to strings. 25 | $params = $this->prepareParameters($params); 26 | 27 | // Build signing string from combined params 28 | $parameterString = new QueryString($params); 29 | 30 | // Remove the port to get around the Magento bug. 31 | // @see http://stackoverflow.com/a/14693714/870667 32 | $requestUrl = $request->getUrl(true); 33 | if (preg_match('@/oauth/(initiate|token)$@', $requestUrl->getPath())) { 34 | $requestUrl->setPort(''); 35 | } 36 | 37 | $url = Url::factory($requestUrl->setQuery('')->setFragment(null)); 38 | 39 | return strtoupper($request->getMethod()) . '&' 40 | . rawurlencode($url) . '&' 41 | . rawurlencode((string) $parameterString); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Magento/Client/Rest/MagentoRestClient.php: -------------------------------------------------------------------------------- 1 | 'http://localhost', 20 | 'base_path' => '', 21 | ); 22 | 23 | $required = array( 24 | 'base_url', 25 | 'base_path', 26 | 'consumer_key', 27 | 'consumer_secret', 28 | ); 29 | 30 | $config = Collection::fromConfig($config, $defaults, $required); 31 | 32 | $magento = new static($config->get('base_url'), $config); 33 | $magento->addSubscriber(new MagentoOauthPlugin($config->toArray())); 34 | 35 | $magento->setDefaultOption('headers', array( 36 | 'Content-Type' => 'application/json', 37 | 'Accept' => '*/*', 38 | )); 39 | 40 | return $magento; 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | * 46 | * Prepends the {+base_path} expressions to the URI 47 | */ 48 | public function createRequest($method = 'GET', $uri = null, $headers = null, $body = null, array $options = array()) 49 | { 50 | $uri = '{+base_path}/' . ltrim($uri, '/'); 51 | return parent::createRequest($method, $uri, $headers, $body, $options); 52 | } 53 | 54 | /** 55 | * @return \Magento\Client\Rest\RequestToken 56 | * 57 | * @throws \Magento\Client\Rest\OauthException 58 | */ 59 | public function getRequestToken() 60 | { 61 | try { 62 | $response = $this->post('/oauth/initiate')->send(); 63 | } catch (ClientErrorResponseException $e) { 64 | throw OauthException::factory($e->getRequest(), $e->getResponse()); 65 | } 66 | return new RequestToken($this, $response); 67 | } 68 | 69 | /** 70 | * @return \Magento\Client\Rest\AccessToken 71 | * 72 | * @throws \Magento\Client\Rest\OauthException 73 | */ 74 | public function getAccessToken() 75 | { 76 | try { 77 | $response = $this->post('/oauth/token')->send(); 78 | } catch (ClientErrorResponseException $e) { 79 | throw OauthException::factory($e->getRequest(), $e->getResponse()); 80 | } 81 | return new AccessToken($this, $response); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Magento/Client/Rest/OauthException.php: -------------------------------------------------------------------------------- 1 | getStatusCode(), 23 | '[reason phrase] ' . $response->getReasonPhrase(), 24 | '[url] ' . $request->getUrl(), 25 | )); 26 | 27 | $e = new static($message); 28 | $e->setResponse($response); 29 | $e->setRequest($request); 30 | 31 | return $e; 32 | } 33 | 34 | /** 35 | * Returns the Magento problem constant. 36 | * 37 | * @return string 38 | */ 39 | public function getOauthProblem() 40 | { 41 | parse_str($this->getResponse()->getBody(true), $arr); 42 | return isset($arr['oauth_problem']) ? $arr['oauth_problem'] : ''; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Magento/Client/Rest/RequestToken.php: -------------------------------------------------------------------------------- 1 | callbackConfirmed = $arr['oauth_callback_confirmed']; 25 | } 26 | 27 | /** 28 | * @return bool 29 | */ 30 | public function callbackConfirmed() 31 | { 32 | return $this->callbackConfirmed; 33 | } 34 | 35 | /** 36 | * @param string $path 37 | * 38 | * @return Guzzle\Http\Url 39 | */ 40 | public function getAuthUrl($path) 41 | { 42 | return Url::factory($this->client->getConfig('base_url')) 43 | ->setPath($path) 44 | ->setQuery(array('oauth_token' => $this->token)) 45 | ; 46 | } 47 | 48 | /** 49 | * @return Guzzle\Http\Url 50 | */ 51 | public function getCustomerAuthUrl() 52 | { 53 | return $this->getAuthUrl('/oauth/authorize'); 54 | } 55 | 56 | /** 57 | * @return Guzzle\Http\Url 58 | */ 59 | public function getAdminAuthUrl() 60 | { 61 | return $this->getAuthUrl('/admin/oauth_authorize'); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Magento/Client/Rest/Token.php: -------------------------------------------------------------------------------- 1 | client = $client; 38 | $this->response = $response; 39 | 40 | parse_str($response->getBody(true), $arr); 41 | if (!isset($arr['oauth_token'])) { 42 | throw new \UnexpectedValueException('Invalid response: missing oauth_token'); 43 | } 44 | if (!isset($arr['oauth_token_secret'])) { 45 | throw new \UnexpectedValueException('Invalid response: missing oauth_token_secret'); 46 | } 47 | 48 | $this->token = $arr['oauth_token']; 49 | $this->tokenSecret = $arr['oauth_token_secret']; 50 | } 51 | 52 | /** 53 | * @param array $arr 54 | */ 55 | public function init(array $arr) {} 56 | 57 | /** 58 | * @return \Magento\Client\Rest\MagentoRestClient 59 | */ 60 | public function getClient() 61 | { 62 | return $this->client; 63 | } 64 | 65 | /** 66 | * @return \Guzzle\Http\Message\Response 67 | */ 68 | public function getResponse() 69 | { 70 | return $this->response; 71 | } 72 | 73 | /** 74 | * @return string 75 | */ 76 | public function getToken() 77 | { 78 | return $this->token; 79 | } 80 | 81 | /** 82 | * @return string 83 | */ 84 | public function getTokenSecret() 85 | { 86 | return $this->tokenSecret; 87 | } 88 | 89 | /** 90 | * @return string 91 | */ 92 | public function __toString() 93 | { 94 | return $this->response->getBody(true); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Magento/Client/Xmlrpc/MagentoXmlrpcClient.php: -------------------------------------------------------------------------------- 1 | '', 29 | ); 30 | 31 | $required = array( 32 | 'base_url', 33 | 'api_user', 34 | 'api_key', 35 | 'session', 36 | ); 37 | 38 | // Instantiate the Acquia Search plugin. 39 | $config = Collection::fromConfig($config, $defaults, $required); 40 | return new static($config->get('base_url'), $config); 41 | } 42 | 43 | /** 44 | * @param bool $autoClose 45 | * 46 | * @return \Magento\Client\Xmlrpc\MagentoXmlrpcClient 47 | */ 48 | public function autoCloseSession($autoClose = true) 49 | { 50 | $this->autoCloseSession = $autoClose; 51 | return $this; 52 | } 53 | 54 | /** 55 | * Ends the session if applicable. 56 | */ 57 | public function __destruct() 58 | { 59 | if ($this->autoCloseSession && $this->client) { 60 | $this->client->call('endSession', array($this->getConfig('session'))); 61 | } 62 | } 63 | 64 | /** 65 | * @return \fXmlRpc\Client 66 | */ 67 | public function getClient() 68 | { 69 | if (!isset($this->client)) { 70 | $uri = rtrim($this->getConfig('base_url'), '/') . '/api/xmlrpc/'; 71 | $bridge = new \fXmlRpc\Transport\GuzzleBridge($this); 72 | $this->client = new \fXmlRpc\Client($uri, $bridge); 73 | } 74 | 75 | return $this->client; 76 | } 77 | 78 | /** 79 | * @return string 80 | */ 81 | public function getSession() 82 | { 83 | $session = $this->getConfig('session'); 84 | 85 | if (!$session) { 86 | $this->autoCloseSession = true; 87 | $session = $this->getClient()->call('login', array( 88 | $this->getConfig('api_user'), 89 | $this->getConfig('api_key') 90 | )); 91 | $this->getConfig()->set('session', $session); 92 | } 93 | 94 | return $session; 95 | } 96 | 97 | /** 98 | * @param string $method 99 | * @param array $params 100 | * 101 | * @return array 102 | * 103 | * @throws \fXmlRpc\Exception\ResponseException 104 | */ 105 | public function call($method, array $params = array()) 106 | { 107 | $params = array($this->getSession(), $method, $params); 108 | return $this->getClient()->call('call', $params); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /test/bootstrap.php: -------------------------------------------------------------------------------- 1 | add('Magento\Client\Test', 'test'); 11 | $loader->register(); 12 | --------------------------------------------------------------------------------