Skip to content

Commit

Permalink
Add support for analyze API
Browse files Browse the repository at this point in the history
  • Loading branch information
const-cloudinary committed Jan 21, 2024
1 parent 57290a5 commit 701dcf0
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 18 deletions.
12 changes: 12 additions & 0 deletions src/Api/Admin/AdminApi.php
Expand Up @@ -11,6 +11,7 @@
namespace Cloudinary\Api\Admin;

use Cloudinary\Api\ApiClient;
use Cloudinary\Configuration\Configuration;

/**
* Enables Cloudinary Admin API functionality.
Expand All @@ -31,12 +32,18 @@ class AdminApi
use UploadMappingsTrait;
use MiscTrait;
use MetadataFieldsTrait;
use AnalysisTrait;

/**
* @var ApiClient $apiClient The API client instance.
*/
protected $apiClient;

/**
* @var ApiClient $apiV2Client The API v2 client instance.
*/
protected $apiV2Client;

/**
* AdminApi constructor.
*
Expand All @@ -46,5 +53,10 @@ class AdminApi
public function __construct($configuration = null)
{
$this->apiClient = new ApiClient($configuration);

$apiV2Configuration = new Configuration($configuration);
$apiV2Configuration->api->apiVersion = '2';

$this->apiV2Client = new ApiClient($apiV2Configuration);
}
}
63 changes: 63 additions & 0 deletions src/Api/Admin/AnalysisTrait.php
@@ -0,0 +1,63 @@
<?php
/**
* This file is part of the Cloudinary PHP package.
*
* (c) Cloudinary
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Cloudinary\Api\Admin;

use Cloudinary\Api\ApiClient;
use Cloudinary\Api\ApiResponse;
use GuzzleHttp\Promise\PromiseInterface;

/**
* Represents Analysis API methods.
*
* @property ApiClient $apiV2Client Defined in AdminApi class.
*
* @api
*/
trait AnalysisTrait
{
/**
* Analyzes an asset with the requested analysis type.
*
* @param string $inputType The type of input for the asset to analyze ('uri').
* @param string $analysisType The type of analysis to run ('google_tagging', 'captioning', 'fashion').
* @param string $uri The URI of the asset to analyze.
*
* @return ApiResponse
*
* @see AdminApi::analyzeAsync()
*
* @see https://cloudinary.com/documentation/media_analyzer_api_reference
*/
public function analyze($inputType, $analysisType, $uri = null)
{
return $this->analyzeAsync($inputType, $analysisType, $uri)->wait();
}

/**
* Analyzes an asset with the requested analysis type asynchronously.
*
* @param string $inputType The type of input for the asset to analyze ('uri').
* @param string $analysisType The type of analysis to run ('google_tagging', 'captioning', 'fashion').
* @param string $uri The URI of the asset to analyze.
*
* @return PromiseInterface
*
* @see https://cloudinary.com/documentation/media_analyzer_api_reference
*/
public function analyzeAsync($inputType, $analysisType, $uri = null)
{
$endPoint = [ApiEndPoint::ANALYSIS, 'analyze'];

$params = ['input_type' => $inputType, 'analysis_type' => $analysisType, 'uri' => $uri];

return $this->apiV2Client->postJsonAsync($endPoint, $params);
}
}
1 change: 1 addition & 0 deletions src/Api/Admin/ApiEndPoint.php
Expand Up @@ -27,4 +27,5 @@ class ApiEndPoint
const UPLOAD_PRESETS = 'upload_presets';
const UPLOAD_MAPPINGS = 'upload_mappings';
const METADATA_FIELDS = 'metadata_fields';
const ANALYSIS = 'analysis';
}
11 changes: 6 additions & 5 deletions src/Api/ApiClient.php
Expand Up @@ -52,7 +52,8 @@ public function __construct($configuration = null)

$this->configuration($configuration);

$this->baseUri = "{$this->api->uploadPrefix}/" . self::apiVersion() . "/{$this->cloud->cloudName}/";
$this->baseUri = "{$this->api->uploadPrefix}/" . self::apiVersion($this->api->apiVersion)
. "/{$this->cloud->cloudName}/";

$this->createHttpClient();
}
Expand Down Expand Up @@ -140,7 +141,7 @@ public function postFormAsync($endPoint, $formParams)
*/
public function postAndSignFormAsync($endPoint, $formParams)
{
if (!$this->cloud->oauthToken) {
if (! $this->cloud->oauthToken) {
ApiUtils::signRequest($formParams, $this->cloud);
}

Expand Down Expand Up @@ -240,7 +241,7 @@ public function postFileAsync($endPoint, $file, $parameters, $options = [])
{
$unsigned = ArrayUtils::get($options, 'unsigned');

if (!$this->cloud->oauthToken && !$unsigned) {
if (! $this->cloud->oauthToken && ! $unsigned) {
ApiUtils::signRequest($parameters, $this->cloud);
}

Expand Down Expand Up @@ -414,11 +415,11 @@ protected function buildHttpClientConfig()

if (isset($this->cloud->oauthToken)) {
$authConfig = [
'headers' => ['Authorization' => 'Bearer ' . $this->cloud->oauthToken]
'headers' => ['Authorization' => 'Bearer ' . $this->cloud->oauthToken],
];
} else {
$authConfig = [
'auth' => [$this->cloud->apiKey, $this->cloud->apiSecret]
'auth' => [$this->cloud->apiKey, $this->cloud->apiSecret],
];
}

Expand Down
13 changes: 5 additions & 8 deletions src/Api/BaseApiClient.php
Expand Up @@ -43,11 +43,6 @@ class BaseApiClient
{
use LoggerTrait;

/**
* @var string Cloudinary API version
*/
const API_VERSION = '1.1';

/**
* @var array Cloudinary API Error Classes mapping between http error codes and Cloudinary exceptions
*/
Expand Down Expand Up @@ -275,13 +270,15 @@ public function putJson($endPoint, $json)
/**
* Gets the API version string from the version.
*
* @param string $apiVersion The API version in the form Major.minor (for example: 1.1).
*
* @return string API version string
*
* @internal
*/
public static function apiVersion()
public static function apiVersion($apiVersion = ApiConfig::DEFAULT_API_VERSION)
{
return 'v' . str_replace('.', '_', self::API_VERSION);
return 'v' . str_replace('.', '_', $apiVersion);
}

/**
Expand Down Expand Up @@ -315,7 +312,7 @@ protected static function finalizeEndPoint($endPoint)
*/
protected function callAsync($method, $endPoint, $options)
{
$endPoint = self::finalizeEndPoint($endPoint);
$endPoint = self::finalizeEndPoint($endPoint);
$options['headers'] = ArrayUtils::mergeNonEmpty(
ArrayUtils::get($options, 'headers', []),
ArrayUtils::get($options, 'extra_headers', [])
Expand Down
2 changes: 1 addition & 1 deletion src/Api/Provisioning/AccountApiClient.php
Expand Up @@ -69,7 +69,7 @@ public function init(ProvisioningConfiguration $configuration = null)
$this->baseUri = sprintf(
'%s/%s/%s/%s/%s/',
$this->api->uploadPrefix,
self::apiVersion(),
self::apiVersion($this->api->apiVersion),
self::PROVISIONING,
self::ACCOUNTS,
$configuration->provisioningAccount->accountId
Expand Down
10 changes: 10 additions & 0 deletions src/Configuration/ApiConfig.php
Expand Up @@ -14,6 +14,7 @@
* Defines the global configuration when making requests to the Cloudinary API.
*
* @property string $uploadPrefix Used for changing default API host.
* @property string $apiVersion Used for changing default API version.
* @property int|float $timeout Describing the timeout of the request in seconds.
* Use 0 to wait indefinitely (the default value is 60 seconds).
* @property int|float $uploadTimeout Describing the timeout of the upload request in seconds.
Expand All @@ -27,11 +28,13 @@ class ApiConfig extends BaseConfigSection
const CONFIG_NAME = 'api';

const DEFAULT_UPLOAD_PREFIX = 'https://api.cloudinary.com';
const DEFAULT_API_VERSION = '1.1';
const DEFAULT_CHUNK_SIZE = 20000000; // bytes
const DEFAULT_TIMEOUT = 60; // seconds

// Supported parameters
const UPLOAD_PREFIX = 'upload_prefix'; // FIXME: rename it! (it is actually prefix for all API calls)
const API_VERSION = 'api_version';
const API_PROXY = 'api_proxy';
const CONNECTION_TIMEOUT = 'connection_timeout';
const TIMEOUT = 'timeout';
Expand All @@ -46,6 +49,13 @@ class ApiConfig extends BaseConfigSection
*/
protected $uploadPrefix;

/**
* Used for changing default API version.
*
* @var string
*/
protected $apiVersion;

/**
* Optional. Specifies a proxy through which to make calls to the Cloudinary API. Format: http://hostname:port.
*
Expand Down
7 changes: 7 additions & 0 deletions tests/Helpers/MockAdminApi.php
Expand Up @@ -11,6 +11,8 @@
namespace Cloudinary\Test\Helpers;

use Cloudinary\Api\Admin\AdminApi;
use Cloudinary\Api\ApiClient;
use Cloudinary\Configuration\Configuration;

/**
* Class MockAdminApi
Expand All @@ -29,5 +31,10 @@ public function __construct($configuration = null)
parent::__construct($configuration);

$this->apiClient = new MockApiClient($configuration);

$apiV2Configuration = new Configuration($configuration);
$apiV2Configuration->api->apiVersion = '2';

$this->apiV2Client = new MockApiClient($apiV2Configuration);
}
}
4 changes: 4 additions & 0 deletions tests/Helpers/MockApiClientTrait.php
Expand Up @@ -98,6 +98,10 @@ static function ($options, $item) {
}
);
}

/**
* @return \string[][]
*/
public function getLastRequestHeaders()
{
return $this->mockHandler->getLastRequest()->getHeaders();
Expand Down
22 changes: 21 additions & 1 deletion tests/Helpers/MockApiTrait.php
Expand Up @@ -27,13 +27,33 @@ public function getMockHandler()
return $this->getApiClient()->mockHandler;
}

/**
* Returns mock handler.
*
* @return MockHandler
*/
public function getV2MockHandler()
{
return $this->getApiV2Client()->mockHandler;
}

/**
* Returns a mock api client.
*
* @return MockApiClient
* @return \Cloudinary\Api\ApiClient|\Cloudinary\Api\UploadApiClient|MockApiClient
*/
public function getApiClient()
{
return $this->apiClient;
}

/**
* Returns a mock api client.
*
* @return \Cloudinary\Api\ApiClient|\Cloudinary\Api\UploadApiClient|MockApiClient
*/
public function getApiV2Client()
{
return $this->apiV2Client;
}
}
8 changes: 5 additions & 3 deletions tests/Helpers/RequestAssertionsTrait.php
Expand Up @@ -92,12 +92,14 @@ protected static function assertRequestFields(RequestInterface $request, $fields
* @param string $path
* @param string $message
*/
protected static function assertRequestUrl(RequestInterface $request, $path, $message = '')
protected static function assertRequestUrl(RequestInterface $request, $path, $message = '', $config = null)
{
$config = Configuration::instance();
if ($config == null) {
$config = Configuration::instance();
}

self::assertEquals(
'/' . ApiClient::apiVersion() . '/' . $config->cloud->cloudName . $path,
'/' . ApiClient::apiVersion($config->api->apiVersion) . '/' . $config->cloud->cloudName . $path,
$request->getUri()->getPath(),
$message
);
Expand Down
50 changes: 50 additions & 0 deletions tests/Unit/Admin/AnalysisTest.php
@@ -0,0 +1,50 @@
<?php
/**
* This file is part of the Cloudinary PHP package.
*
* (c) Cloudinary
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Cloudinary\Test\Unit\Admin;

use Cloudinary\Api\Exception\ApiError;
use Cloudinary\Configuration\Configuration;
use Cloudinary\Test\Helpers\MockAdminApi;
use Cloudinary\Test\Helpers\RequestAssertionsTrait;
use Cloudinary\Test\Integration\IntegrationTestCase;
use Cloudinary\Test\Unit\Asset\AssetTestCase;
use Cloudinary\Test\Unit\UnitTestCase;

/**
* Class AnalysisTest
*/
final class AnalysisTest extends UnitTestCase
{
use RequestAssertionsTrait;

/**
* Test analyze.
*/
public function testAnalyze()
{
$mockAdminApi = new MockAdminApi();
$mockAdminApi->analyze("uri", "captioning", "https://res.cloudinary.com/demo/image/upload/dog");

$lastRequest = $mockAdminApi->getV2MockHandler()->getLastRequest();
$apiV2Configuration = new Configuration();
$apiV2Configuration->api->apiVersion = '2';

self::assertRequestUrl($lastRequest, '/analysis/analyze', "", $apiV2Configuration);
self::assertRequestJsonBodySubset(
$lastRequest,
[
"input_type"=> "uri",
"analysis_type"=> "captioning",
"uri"=> "https://res.cloudinary.com/demo/image/upload/dog",
]
);
}
}

0 comments on commit 701dcf0

Please sign in to comment.