PHP: Guzzle Client - Proxy request to different server - php

So, I am just trying to proxy all requests to a different server.
I want everything to be the same, except I want to change the base uri.
<?php
namespace App\MicroServices\Example\Clients;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
/**
* Class ExampleClient
* #package App\MicroServices\Example\Clients
*/
class ExampleClient extends Client implements ClientInterface
{
/**
* ExampleClient constructor.
*/
public function __construct()
{
parent::__construct([
'base_uri' => config('example.base.uri'),
'timeout' => config('example.client.timeout'),
]);
}
/**
* #param Request $request
*
* #return string
*
* #throws \GuzzleHttp\Exception\GuzzleException
*/
public function proxyToExampleServer(Request $request)
{
$method = $request->getMethod();
$body = json_decode($request->getContent(), true);
$path = $request->path() . ($request->getQueryString() ? ('?' . $request->getQueryString()) : '');
$headers = [];
foreach ($request->header() as $key => $value)
{
$headers[$key] = $value[0];
}
$headers['Authorization'] = $request->bearerToken();
return $this->request($method, $path, ['headers' => $headers, 'body' => $body])->getBody()->getContents();
}
}
Response in Postman is 400 Bad Request, I have tried changing to 'form_params' and 'json'
Any thoughts?

So, I got it working with this function
/**
* #param Request $request
*
* #return string
*
* #throws \GuzzleHttp\Exception\GuzzleException
*/
public function proxyToExampleServer(Request $request)
{
$method = $request->getMethod();
$body = json_decode($request->getContent(), true);
$path = $request->path() . ($request->getQueryString() ? ('?' . $request->getQueryString()) : '');
$headers = $request->header();
try {
return $this->request($method, $path, ['headers' => $headers, 'json' => $body])->getBody()->getContents();
} catch (ClientException $exception) {
return $exception->getResponse();
}
}

Related

Why Cloudfront returning 403 with Guzzle?

I'm consuming a API that uses the CloudFront service,
And I'm getting a 403 error for the requests with Guzzle, but if uses for example PHP Curl or call via Postman or Browser works.
Here a log of the Guzzle:
Log of guzzle
And here part of code:
/**
* #return void
*/
public function __construct()
{
$this->client = new Client([
'base_uri' => env('API_HOST'),
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
],
'timeout' => 30,
'debug' => true,
]);
}
/**
* #param string $method
* #param string $url
* #param array $body
* #param bool $isMultipart
*
* #return ResponseInterface
*/
private function request(string $method, string $url, array $body = [], bool $isMultipart = false): ResponseInterface
{
if ($isMultipart) {
$params['multipart'] = [$body];
} else {
$params['json'] = $body;
}
$url = $this->appedAuthTokensToUrl($url);
return $this->client->request($method, $url, $params);
}
Finally found solution. If had a body in the GET request the Cloudfront will return 403.
So in my case the problem is this if (always setting a body):
if ($isMultipart) {
$params['multipart'] = [$body];
} else {
$params['json'] = $body;
}
Here link of Cloudfront docs

How to pass storeUrl to default Magento oauth script?

I'm trying to create my first Magento 2 extension and integration and I've been following the guide in their docs here. All good so far, I've completed the auth handshake, stored all the required keys for api requests and can make requests back to my extension fine.
Looking at the OauthClient.php script provided at the foot of the tutorial, the url is hardcoded like so:
return new Uri('http://magento.host/oauth/token/request'); and the tutorial advises you to "Change the instances of http://magento.host in this example to a valid base URL."
<?php
use OAuth\Common\Consumer\Credentials;
use OAuth\Common\Http\Client\ClientInterface;
use OAuth\Common\Http\Exception\TokenResponseException;
use OAuth\Common\Http\Uri\Uri;
use OAuth\Common\Http\Uri\UriInterface;
use OAuth\Common\Storage\TokenStorageInterface;
use OAuth\OAuth1\Service\AbstractService;
use OAuth\OAuth1\Signature\SignatureInterface;
use OAuth\OAuth1\Token\StdOAuth1Token;
use OAuth\OAuth1\Token\TokenInterface;
class OauthClient extends AbstractService
{
/** #var string|null */
protected $_oauthVerifier = null;
public function __construct(
Credentials $credentials,
ClientInterface $httpClient = null,
TokenStorageInterface $storage = null,
SignatureInterface $signature = null,
UriInterface $baseApiUri = null
) {
if (!isset($httpClient)) {
$httpClient = new \OAuth\Common\Http\Client\StreamClient();
}
if (!isset($storage)) {
$storage = new \OAuth\Common\Storage\Session();
}
if (!isset($signature)) {
$signature = new \OAuth\OAuth1\Signature\Signature($credentials);
}
parent::__construct($credentials, $httpClient, $storage, $signature, $baseApiUri);
}
/**
* #return UriInterface
*/
public function getRequestTokenEndpoint()
{
return new Uri('http://magento.host/oauth/token/request');
}
/**
* Returns the authorization API endpoint.
*
* #throws \OAuth\Common\Exception\Exception
*/
public function getAuthorizationEndpoint()
{
throw new \OAuth\Common\Exception\Exception(
'Magento REST API is 2-legged. Current operation is not available.'
);
}
/**
* Returns the access token API endpoint.
*
* #return UriInterface
*/
public function getAccessTokenEndpoint()
{
return new Uri('http://magento.host/oauth/token/access');
}
/**
* Parses the access token response and returns a TokenInterface.
*
* #param string $responseBody
* #return TokenInterface
*/
protected function parseAccessTokenResponse($responseBody)
{
return $this->_parseToken($responseBody);
}
/**
* Parses the request token response and returns a TokenInterface.
*
* #param string $responseBody
* #return TokenInterface
* #throws TokenResponseException
*/
protected function parseRequestTokenResponse($responseBody)
{
$data = $this->_parseResponseBody($responseBody);
if (isset($data['oauth_verifier'])) {
$this->_oauthVerifier = $data['oauth_verifier'];
}
return $this->_parseToken($responseBody);
}
/**
* Parse response body and create oAuth token object based on parameters provided.
*
* #param string $responseBody
* #return StdOAuth1Token
* #throws TokenResponseException
*/
protected function _parseToken($responseBody)
{
$data = $this->_parseResponseBody($responseBody);
$token = new StdOAuth1Token();
$token->setRequestToken($data['oauth_token']);
$token->setRequestTokenSecret($data['oauth_token_secret']);
$token->setAccessToken($data['oauth_token']);
$token->setAccessTokenSecret($data['oauth_token_secret']);
$token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
unset($data['oauth_token'], $data['oauth_token_secret']);
$token->setExtraParams($data);
return $token;
}
/**
* Parse response body and return data in array.
*
* #param string $responseBody
* #return array
* #throws \OAuth\Common\Http\Exception\TokenResponseException
*/
protected function _parseResponseBody($responseBody)
{
if (!is_string($responseBody)) {
throw new TokenResponseException("Response body is expected to be a string.");
}
parse_str($responseBody, $data);
if (null === $data || !is_array($data)) {
throw new TokenResponseException('Unable to parse response.');
} elseif (isset($data['error'])) {
throw new TokenResponseException("Error occurred: '{$data['error']}'");
}
return $data;
}
/**
* #override to fix since parent implementation from lib not sending the oauth_verifier when requesting access token
* Builds the authorization header for an authenticated API request
*
* #param string $method
* #param UriInterface $uri the uri the request is headed
* #param \OAuth\OAuth1\Token\TokenInterface $token
* #param $bodyParams array
* #return string
*/
protected function buildAuthorizationHeaderForAPIRequest(
$method,
UriInterface $uri,
TokenInterface $token,
$bodyParams = null
) {
$this->signature->setTokenSecret($token->getAccessTokenSecret());
$parameters = $this->getBasicAuthorizationHeaderInfo();
if (isset($parameters['oauth_callback'])) {
unset($parameters['oauth_callback']);
}
$parameters = array_merge($parameters, ['oauth_token' => $token->getAccessToken()]);
$parameters = array_merge($parameters, $bodyParams);
$parameters['oauth_signature'] = $this->signature->getSignature($uri, $parameters, $method);
$authorizationHeader = 'OAuth ';
$delimiter = '';
foreach ($parameters as $key => $value) {
$authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"';
$delimiter = ', ';
}
return $authorizationHeader;
}
}
My Question is how do I pass the url from the store that the integration has been set up on back as a variable in here?(I have it stored in my db)
Thanks for taking the time to take a look.
For anyone who might come across this in future after getting the saved data from the table in my db, I added the Url into the call to make the new class on the checklogin.php script in the documentation:
$oAuthClient = new OauthClient($credentials,$magentoBaseUrl);
And then in OauthClient.php, I added the url to the construct and updated the getRequestTokenEndpoint method and the getAcessTokenEndpoint:
public function __construct(
Credentials $credentials,
$magentoBaseUrl = null,
ClientInterface $httpClient = null,
TokenStorageInterface $storage = null,
SignatureInterface $signature = null,
UriInterface $baseApiUri = null
) {
if (!isset($httpClient)) {
$httpClient = new \OAuth\Common\Http\Client\CurlClient();
}
if (!isset($storage)) {
$storage = new \OAuth\Common\Storage\Session();
}
if (!isset($signature)) {
$signature = new \OAuth\OAuth1\Signature\Signature($credentials);
}
if (!isset($magentoBaseUrl)) {
die();
}
$this->magentoBaseUrl = $magentoBaseUrl;
parent::__construct($credentials, $httpClient, $storage, $signature, $baseApiUri);
}
...
/**
* #return UriInterface
*/
public function getRequestTokenEndpoint()
{
return new Uri($this->magentoBaseUrl.'/oauth/token/request');
}
...
/**
* Returns the access token API endpoint.
*
* #return UriInterface
*/
public function getAccessTokenEndpoint()
{
return new Uri($this->magentoBaseUrl.'/oauth/token/access');
}

Unit testing with mock [Symfony 4 api]

I want to test my controller's functions with PHP unit using MOCK (in an API symfony 4) but i can't find a way to.
In fact i have do several research and coudn't find a way to do it, I installed PHP unit and coded a test web case without mock and it's work it but not by mock. i want to use mocking because i don't want to touch the database.
Anyone can help me please to achieve that .
This is my controller:
<?php
namespace App\Controller;
use App\Utils\MatchServiceInterface;
use App\Utils\ModeServiceInterface;
use App\Utils\PlayerServiceInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
/**
* #Route("/api/scouters/matchs")
* Manage entity Match
* Class MatchController
* #package App\Controller
*/
class MatchController extends AbstractController
{
private $playerService;
private $modeService;
private $matchService;
/**
* ScouterController constructor.
* #param PlayerServiceInterface $playerService
* #param ModeServiceInterface $modeService
* #param MatchServiceInterface $matchService
*/
public function __construct(PlayerServiceInterface $playerService, ModeServiceInterface $modeService, MatchServiceInterface $matchService)
{
$this->playerService = $playerService;
$this->modeService = $modeService;
$this->matchService = $matchService;
}
/**
* #Route("/create", name="create_match", methods={"POST"})
* #param Request $request
* #return JsonResponse
*/
public function createMatch(Request $request): JsonResponse
{
$content = json_decode($request->getContent(), true);
$message = $this->playerService->assignPlayerToMatch($content);
return new JsonResponse($message, JsonResponse::HTTP_OK);
}
/**
* #Route("/mode", name="mode_match", methods={"POST"})
* #param Request $request
* #return JsonResponse
* #return JsonResponse
*/
public function modeMatch(Request $request): JsonResponse
{
$content = json_decode($request->getContent(), true);
$message = $this->modeService->assignModeToMatch($content);
return new JsonResponse($message, JsonResponse::HTTP_OK);
}
/**
* #Route("/features", name="feat_mode_match", methods={"POST"})
* #param Request $request
* #return JsonResponse
*/
public function featMode(Request $request): JsonResponse
{
$content = json_decode($request->getContent(), true);
$this->matchService->modeFeature($content);
$message = $this->matchService->modeFeature($content);
return new JsonResponse($message, JsonResponse::HTTP_OK);
}
}
this is an example of test of my login function ,
/**
* test ScouterController:login
*/
public function testLogin()
{
$data = ['email' => 'meher.jaber#solixy.com', 'password' => 'FootStat#2019'];
$client = static::createClient();
$request = $client->request('POST', '/api/scouter/login', [], [], [], json_encode($data));
$response = $client->getResponse();
$this->assertSame('"EmailPasswordValidAndHasNotPlayer"', $response->getContent());
$this->assertSame(200, $response->getStatusCode());
}
Login function :
/**
* Login Scouter
* #Route("/login", name="login_scouter", methods={"POST"})
* #param Request $request
* #return JsonResponse
*/
public function login(Request $request): JsonResponse
{
$content = json_decode($request->getContent(), true);
$message = $this->securityService->loginScouter($content);
$this->securityService->loginScouter($content);
return new JsonResponse($message, JsonResponse::HTTP_OK);
}
Login service :
/**
* #param $content
* #return array|string
*/
public function loginScouter($content)
{
$scouter = $this->em->getRepository(Scouter::class)->findOneBy(['email' => $content['email']]);
if ($scouter) {
/* #var $scouter Scouter */
if ($this->encoder->isPasswordValid($scouter, $content['password'])) {
if (is_null($scouter->getPlayer())) {
$message = "EmailPasswordValidHasNotPlayer";
} else {
/* #var $player Player */
$player = $scouter->getPlayer();
/* #var $lastMatch Match */
$lastMatch = $this->em->getRepository(Match::class)->findLastInserted($player->getId());
$message = ['idPlayer' => $player->getId(), 'firstName' => $player->getFirstName(), 'lastName' => $player->getFamilyName(), 'team' => $lastMatch->getTeam(), 'oppTeam' => $lastMatch->getOppositeTeam()];
}
} else {
$message = "PasswordInvalid";
}
} else {
$message = "EmailInvalid";
}
return $message;
}

Task runs on my local machine but not production Laravel Lumen

I am having an issue with my production env. On my local machine when I run the command I built:
php artisan updateusers:badcustomernumbers
everything runs as expected, no jobs fail.
When I deployed and tried to run this same task I get:
Symfony\Component\Debug\Exception\FatalThrowableError: Call to undefined method App\Services\MiddlewareApi::get_lowest_active_customer_number_by_email() in .../app/Jobs/UpdateBadCustomerNumbersJob.php:48
Here is UpdateBadCustomerNumbersJob.php:
<?php
namespace App\Jobs;
use App\AppUser;
use Illuminate\Support\Facades\Log;
use App\Subscription;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Mockery\Exception;
use App\Http\Controllers\UpdateUserController;
use App\Services\MiddlewareApi;
class UpdateBadCustomerNumbersJob extends Job
{
/**
* App users to update customer number for
* #var AppUser
*/
protected $appUsers;
/**
* The number of times the job may be attempted.
*
* #var int
*/
public $tries = 2;
/**
* UpdateBadCustomerNumbersJob constructor.
* #param $appUsers
*/
public function __construct($appUsers)
{
$this->appUsers = $appUsers;
}
/**
* #param UpdateUserController $updateUserController
*/
public function handle(UpdateUserController $updateUserController)
{
$middlewareApi = new MiddlewareApi();
foreach ($this->appUsers as $user) {
$userCustomerNumber = $middlewareApi->get_lowest_active_customer_number_by_email($user->email);
if(!is_null($userCustomerNumber) AND $userCustomerNumber !== false AND !empty($userCustomerNumber->customerNumber)) {
$updateUserController->updateAggregateCustomerNumber($user, $userCustomerNumber, true);
$updateUserController->updateAppDatasCustomerNumber($user, $userCustomerNumber, true);
$updateUserController->updateSubscriptionsCustomerNumber($user, $userCustomerNumber, true);
$updateUserController->updateAppUserCustomerNumber($user, $userCustomerNumber, true);
} else {
//if there is no customer number available just delete this user because they must not have any active subscriptions any longer
$updateUserController->deleteAggregateData($user);
$updateUserController->deleteAppDatas($user);
$updateUserController->deleteSubscriptions($user);
$updateUserController->deleteAppUser($user);
}
}
}
}
and here is MiddlewareAPI.php:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Log;
use Mockery\Exception;
use GuzzleHttp\Client;
class MiddlewareApi
{
/**
* #var $middlewareToken
*/
private $middlewareToken;
/**
* #var $middlewareUrl
*/
private $middlewareUrl;
public function __construct()
{
$this->setMiddlewareToken(env('MIDDLEWARE_TOKEN'));
$this->setMiddlewareUrl(env('MIDDLEWARE_BASE_URL'));
}
/**
* Sets the Middleware API Token
* #param $token
*/
public function setMiddlewareToken( $token )
{
$this->middlewareToken = $token;
}
/**
* Gets the Middleware API Token
* #return mixed
*/
public function getMiddlewareToken()
{
return $this->middlewareToken;
}
/**
* Sets the Middleware base url
* #param $url
*/
public function setMiddlewareUrl( $url )
{
$this->middlewareUrl = $url;
}
/**
* Gets the Middleware base url
* #return mixed
*/
public function getMiddlewareUrl()
{
return $this->middlewareUrl;
}
/**
* Retrieves the Active subscriptions of a customer
* based on customer number
* #param $customerNumber
* #return bool|mixed
*/
public function get_customer_subscriptions_by_customer_number( $customerNumber )
{
$url = $this->getMiddlewareUrl() . 'sub/active/customernumber/' . $customerNumber;
$header = ['Token' => $this->getMiddlewareToken()];
$errorText = 'Error in get_customer_subscriptions_by_customer_number: ';
return $this->_get($url,$header,$errorText);
}
/**
* Retrieves the Active subscriptions and Products of a customer
* #param $customerNumber
* #return bool|mixed
*/
public function get_customer_subscriptions_and_products_by_customer_number( $customerNumber )
{
$url = $this->getMiddlewareUrl() . 'data/customernumber/' . $customerNumber;
$header = ['Token' => $this->getMiddlewareToken()];
$errorText = 'Error in get_customer_subscriptions_by_customer_number: ';
return $this->_get($url,$header,$errorText);
}
/**
* Retrieve the lowest active customer number by email address
* #param $email
* #return bool|mixed
*/
public function get_lowest_active_customer_number_by_email( $email )
{
$url = $this->getMiddlewareUrl() . 'customer/findlowestactivecustomernumber/emailaddress/' . $email;
$header = ['Token' => $this->getMiddlewareToken()];
$errorText = 'Error in get_lowest_active_customer_number_by_email: ';
return $this->_get($url, $header, $errorText);
}
/**
* Get method to make all get calls from middleware
* #param $endpoint
* #param $headers
* #param $errorText
* #return bool|mixed
*/
public function _get($endpoint, $headers, $errorText)
{
$client = new Client();
try {
$response = $client->request('GET', $endpoint,
['headers' => $headers]
);
$responseData = json_decode($response->getBody()->getContents());
return $responseData;
} catch (Exception $e) {
Log::error($errorText. $e);
return false;
}
}
/**
* Returns data with status code in json format
* #param $statusCode
* #param $data
* #return \Illuminate\Http\JsonResponse
*/
public function apiReturnResponseInJson( $statusCode, $data )
{
$content = ['status' => $statusCode, 'data' => $data];
return response()->json($content, $statusCode);
}
}
I tried running composer update and php artisan cache:clear but I am still getting the same error. I even ssh'd in and get_lowest_active_customer_number_by_email method is present in MiddlewareApi.php.
Any ideas what the problem may be?

PHP API Call function is not working

I have a Question about calling a other script.
I want to make an api whit ExactOnline... But i need to call an other script for that I used "require DIR ." That works fine but my code still doesn't get the script. Can someone explane to me why this is not working?
(My script that need to call is in "C:\xampp\htdocs\CM\EO\exactphpclientmaster\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php")
=ERROR=
Fatal error: Class 'vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection' not found in C:\xampp\htdocs\CM\EO\exactphpclientmaster\ConntectEO.php on line 3
=SCRIPT That is calling connection.php=
<?php
require __DIR__ . '\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php';
$connection = new \vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php();
$connection->setRedirectUrl('**************************'); // Same as entered online in the App Center
$connection->setExactClientId('****************************************');
$connection->setExactClientSecret('************************');
if (getValue('authorizationcode')) // Retrieves authorizationcode from database
$connection->setAuthorizationCode(getValue('authorizationcode'));
if (getValue('accesstoken')) // Retrieves accesstoken from database
$connection->setAccessToken(unserialize(getValue('accesstoken')));
if (getValue('refreshtoken')) // Retrieves refreshtoken from database
$connection->setRefreshToken(getValue('refreshtoken'));
if (getValue('expires_in')) // Retrieves expires timestamp from database
$connection->setTokenExpires(getValue('expires_in'));
// Make the client connect and exchange tokens
try {
$connection->connect();
} catch (\Exception $e)
{
throw new Exception('Could not connect to Exact: ' . $e->getMessage());
}
// Save the new tokens for next connections
setValue('accesstoken', serialize($connection->getAccessToken()));
setValue('refreshtoken', $connection->getRefreshToken());
// Optionally, save the expiry-timestamp. This prevents exchanging valid tokens (ie. saves you some requests)
setValue('expires_in', $connection->getTokenExpires());
=SCRIPT Connection.php=
<?php namespace Picqer\Financials\Exact;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7;
/**
* Class Connection
*
* #package Picqer\Financials\Exact
*
*/
class Connection
{
/**
* #var string
*/
private $baseUrl = 'https://start.exactonline.nl';
/**
* #var string
*/
private $apiUrl = '/api/v1';
/**
* #var string
*/
private $authUrl = '/api/oauth2/auth';
/**
* #var string
*/
private $tokenUrl = '/api/oauth2/token';
/**
* #var
*/
private $exactClientId;
/**
* #var
*/
private $exactClientSecret;
/**
* #var
*/
private $authorizationCode;
/**
* #var
*/
private $accessToken;
/**
* #var
*/
private $tokenExpires;
/**
* #var
*/
private $refreshToken;
/**
* #var
*/
private $redirectUrl;
/**
* #var
*/
private $division;
/**
* #var Client
*/
private $client;
/**
* #var callable(Connection)
*/
private $tokenUpdateCallback;
/**
*
*/
protected $middleWares = [];
/**
* #var
*/
public $nextUrl = null;
/**
* #return Client
*/
private function client()
{
if ($this->client) {
return $this->client;
}
$handlerStack = HandlerStack::create();
foreach ($this->middleWares as $middleWare) {
$handlerStack->push($middleWare);
}
$this->client = new Client([
'http_errors' => true,
'handler' => $handlerStack,
'expect' => false,
]);
return $this->client;
}
public function insertMiddleWare($middleWare)
{
$this->middleWares[] = $middleWare;
}
public function connect()
{
// Redirect for authorization if needed (no access token or refresh token given)
if ($this->needsAuthentication()) {
$this->redirectForAuthorization();
}
// If access token is not set or token has expired, acquire new token
if (empty($this->accessToken) || $this->tokenHasExpired()) {
$this->acquireAccessToken();
}
$client = $this->client();
return $client;
}
/**
* #param string $method
* #param $endpoint
* #param null $body
* #param array $params
* #param array $headers
* #return Request
*/
private function createRequest($method = 'GET', $endpoint, $body = null, array $params = [], array $headers = [])
{
// Add default json headers to the request
$headers = array_merge($headers, [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Prefer' => 'return=representation'
]);
// If access token is not set or token has expired, acquire new token
if (empty($this->accessToken) || $this->tokenHasExpired()) {
$this->acquireAccessToken();
}
// If we have a token, sign the request
if (!$this->needsAuthentication() && !empty($this->accessToken)) {
$headers['Authorization'] = 'Bearer ' . $this->accessToken;
}
// Create param string
if (!empty($params)) {
$endpoint .= '?' . http_build_query($params);
}
// Create the request
$request = new Request($method, $endpoint, $headers, $body);
return $request;
}
/**
* #param $url
* #param array $params
* #return mixed
* #throws ApiException
*/
public function get($url, array $params = [])
{
$url = $this->formatUrl($url, $url !== 'current/Me', $url == $this->nextUrl);
try {
$request = $this->createRequest('GET', $url, null, $params);
$response = $this->client()->send($request);
return $this->parseResponse($response, $url != $this->nextUrl);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #param $body
* #return mixed
* #throws ApiException
*/
public function post($url, $body)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('POST', $url, $body);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #param $body
* #return mixed
* #throws ApiException
*/
public function put($url, $body)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('PUT', $url, $body);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #return mixed
* #throws ApiException
*/
public function delete($url)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('DELETE', $url);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #return string
*/
public function getAuthUrl()
{
return $this->baseUrl . $this->authUrl . '?' . http_build_query(array(
'client_id' => $this->exactClientId,
'redirect_uri' => $this->redirectUrl,
'response_type' => 'code'
));
}
/**
* #param mixed $exactClientId
*/
public function setExactClientId($exactClientId)
{
$this->exactClientId = $exactClientId;
}
/**
* #param mixed $exactClientSecret
*/
public function setExactClientSecret($exactClientSecret)
{
$this->exactClientSecret = $exactClientSecret;
}
/**
* #param mixed $authorizationCode
*/
public function setAuthorizationCode($authorizationCode)
{
$this->authorizationCode = $authorizationCode;
}
/**
* #param mixed $accessToken
*/
public function setAccessToken($accessToken)
{
$this->accessToken = $accessToken;
}
/**
* #param mixed $refreshToken
*/
public function setRefreshToken($refreshToken)
{
$this->refreshToken = $refreshToken;
}
/**
*
*/
public function redirectForAuthorization()
{
$authUrl = $this->getAuthUrl();
header('Location: ' . $authUrl);
exit;
}
/**
* #param mixed $redirectUrl
*/
public function setRedirectUrl($redirectUrl)
{
$this->redirectUrl = $redirectUrl;
}
/**
* #return bool
*/
public function needsAuthentication()
{
return empty($this->refreshToken) && empty($this->authorizationCode);
}
/**
* #param Response $response
* #param bool $returnSingleIfPossible
* #return mixed
* #throws ApiException
*/
private function parseResponse(Response $response, $returnSingleIfPossible = true)
{
try {
if ($response->getStatusCode() === 204) {
return [];
}
Psr7\rewind_body($response);
$json = json_decode($response->getBody()->getContents(), true);
if (array_key_exists('d', $json)) {
if (array_key_exists('__next', $json['d'])) {
$this->nextUrl = $json['d']['__next'];
}
else {
$this->nextUrl = null;
}
if (array_key_exists('results', $json['d'])) {
if ($returnSingleIfPossible && count($json['d']['results']) == 1) {
return $json['d']['results'][0];
}
return $json['d']['results'];
}
return $json['d'];
}
return $json;
} catch (\RuntimeException $e) {
throw new ApiException($e->getMessage());
}
}
/**
* #return mixed
*/
private function getCurrentDivisionNumber()
{
if (empty($this->division)) {
$me = new Me($this);
$this->division = $me->find()->CurrentDivision;
}
return $this->division;
}
/**
* #return mixed
*/
public function getRefreshToken()
{
return $this->refreshToken;
}
/**
* #return mixed
*/
public function getAccessToken()
{
return $this->accessToken;
}
private function acquireAccessToken()
{
// If refresh token not yet acquired, do token request
if (empty($this->refreshToken)) {
$body = [
'form_params' => [
'redirect_uri' => $this->redirectUrl,
'grant_type' => 'authorization_code',
'client_id' => $this->exactClientId,
'client_secret' => $this->exactClientSecret,
'code' => $this->authorizationCode
]
];
} else { // else do refresh token request
$body = [
'form_params' => [
'refresh_token' => $this->refreshToken,
'grant_type' => 'refresh_token',
'client_id' => $this->exactClientId,
'client_secret' => $this->exactClientSecret,
]
];
}
$response = $this->client()->post($this->getTokenUrl(), $body);
if ($response->getStatusCode() == 200) {
Psr7\rewind_body($response);
$body = json_decode($response->getBody()->getContents(), true);
if (json_last_error() === JSON_ERROR_NONE) {
$this->accessToken = $body['access_token'];
$this->refreshToken = $body['refresh_token'];
$this->tokenExpires = $this->getDateTimeFromExpires($body['expires_in']);
if (is_callable($this->tokenUpdateCallback)) {
call_user_func($this->tokenUpdateCallback, $this);
}
} else {
throw new ApiException('Could not acquire tokens, json decode failed. Got response: ' . $response->getBody()->getContents());
}
} else {
throw new ApiException('Could not acquire or refresh tokens');
}
}
private function getDateTimeFromExpires($expires)
{
if (!is_numeric($expires)) {
throw new \InvalidArgumentException('Function requires a numeric expires value');
}
return time() + 600;
}
/**
* #return mixed
*/
public function getTokenExpires()
{
return $this->tokenExpires;
}
/**
* #param mixed $tokenExpires
*/
public function setTokenExpires($tokenExpires)
{
$this->tokenExpires = $tokenExpires;
}
private function tokenHasExpired()
{
if (empty($this->tokenExpires)) {
return true;
}
return $this->tokenExpires <= time() + 10;
}
private function formatUrl($endPoint, $includeDivision = true, $formatNextUrl = false)
{
if ($formatNextUrl) {
return $endPoint;
}
if ($includeDivision) {
return implode('/', [
$this->getApiUrl(),
$this->getCurrentDivisionNumber(),
$endPoint
]);
}
return implode('/', [
$this->getApiUrl(),
$endPoint
]);
}
/**
* #return mixed
*/
public function getDivision()
{
return $this->division;
}
/**
* #param mixed $division
*/
public function setDivision($division)
{
$this->division = $division;
}
/**
* #param callable $callback
*/
public function setTokenUpdateCallback($callback) {
$this->tokenUpdateCallback = $callback;
}
/**
* Parse the reponse in the Exception to return the Exact error messages
* #param Exception $e
* #throws ApiException
*/
private function parseExceptionForErrorMessages(Exception $e)
{
if (! $e instanceof BadResponseException) {
throw new ApiException($e->getMessage());
}
$response = $e->getResponse();
Psr7\rewind_body($response);
$responseBody = $response->getBody()->getContents();
$decodedResponseBody = json_decode($responseBody, true);
if (! is_null($decodedResponseBody) && isset($decodedResponseBody['error']['message']['value'])) {
$errorMessage = $decodedResponseBody['error']['message']['value'];
} else {
$errorMessage = $responseBody;
}
throw new ApiException('Error ' . $response->getStatusCode() .': ' . $errorMessage);
}
/**
* #return string
*/
protected function getBaseUrl()
{
return $this->baseUrl;
}
/**
* #return string
*/
private function getApiUrl()
{
return $this->baseUrl . $this->apiUrl;
}
/**
* #return string
*/
private function getTokenUrl()
{
return $this->baseUrl . $this->tokenUrl;
}
/**
* Set base URL for different countries according to
* https://developers.exactonline.com/#Exact%20Online%20sites.html
*
* #param string $baseUrl
*/
public function setBaseUrl($baseUrl)
{
$this->baseUrl = $baseUrl;
}
/**
* #param string $apiUrl
*/
public function setApiUrl($apiUrl)
{
$this->apiUrl = $apiUrl;
}
/**
* #param string $authUrl
*/
public function setAuthUrl($authUrl)
{
$this->authUrl = $authUrl;
}
/**
* #param string $tokenUrl
*/
public function setTokenUrl($tokenUrl)
{
$this->tokenUrl = $tokenUrl;
}
}
The error itself is pretty self-explanatory. You are trying to include a file and it cannot be found with the path you provided.
Try printing what the magic constant __DIR__ contains in order to see the full path you are trying to include.
You can use var_dump(__DIR__);exit; at the start of your script.
As an additional note, you should consider using composer's autoload.
As you mention your trying to load Connection class as below
require __DIR__ . '\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php';
When we using composer, instead of loading individual class files try to use composer auto load, its automatically loads the name spaces of the required class.
If you implement auto load in your code, the code may look like this.
require __DIR__ . '/vendor/autoload.php';
use Picqer\Financials\Exact\Connection;
$connection = new Connection();

Categories