Skip to content

Commit

Permalink
Add support for SearchFolders API
Browse files Browse the repository at this point in the history
  • Loading branch information
const-cloudinary committed Jan 12, 2023
1 parent 7808149 commit 8087ddb
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 27 deletions.
50 changes: 40 additions & 10 deletions src/Api/SearchApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@
*/
class SearchApi implements JsonSerializable
{
/**
* @internal
*/
const SEARCH_API_ENDPOINT = 'resources/search';
/**
* @internal
*/
Expand Down Expand Up @@ -67,15 +63,25 @@ class SearchApi implements JsonSerializable
* @internal
*/
const KEYS_WITH_UNIQUE_VALUES = [self::SORT_BY, self::AGGREGATE, self::WITH_FIELD];
/**
* @internal
*/
const ASSETS = 'resources';

/**
* @var string The Search API endpoint.
*/
private $endpoint = self::ASSETS;

/**
* @var array query object that includes the search query
*/
private $query = [
self::SORT_BY => [],
self::AGGREGATE => [],
self::WITH_FIELD => [],
];
private $query
= [
self::SORT_BY => [],
self::AGGREGATE => [],
self::WITH_FIELD => [],
];

/**
* @var ApiClient $apiClient The HTTP API client instance.
Expand All @@ -92,6 +98,20 @@ public function __construct($configuration = null)
$this->apiClient = new ApiClient($configuration);
}

/**
* Sets the Search API endpoint.
*
* @param string $endpoint The endpoint for the Search API.
*
* @return $this
*/
public function endpoint($endpoint)
{
$this->endpoint = $endpoint;

return $this;
}

/**
* Sets the query string for filtering the assets in your cloud.
*
Expand Down Expand Up @@ -211,7 +231,7 @@ public function withField($value)
*/
public function executeAsync()
{
return $this->apiClient->postJsonAsync(self::SEARCH_API_ENDPOINT, $this);
return $this->apiClient->postJsonAsync($this->getSearchEndpoint(), $this);
}

/**
Expand Down Expand Up @@ -261,4 +281,14 @@ public function jsonSerialize()
{
return $this->asArray();
}

/**
* Returns the search endpoint.
*
* @return string
*/
private function getSearchEndpoint()
{
return "{$this->endpoint}/search";
}
}
39 changes: 39 additions & 0 deletions src/Api/SearchFoldersApi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?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\Search;

/**
* Class SearchFoldersApi
*
* The Cloudinary API folders search method allows you fine control on filtering and retrieving information on all the
* folders in your cloud with the help of query expressions in a Lucene-like query language.
*
* @api
*/
class SearchFoldersApi extends SearchApi
{
/**
* @internal
*/
const FOLDERS = 'folders';

/**
* SearchFoldersApi constructor.
*
* @param mixed $configuration
*/
public function __construct($configuration = null)
{
parent::__construct($configuration);

$this->endpoint(self::FOLDERS);
}
}
11 changes: 11 additions & 0 deletions src/Cloudinary.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace Cloudinary;

use Cloudinary\Api\Admin\AdminApi;
use Cloudinary\Api\Search\SearchFoldersApi;
use Cloudinary\Api\Search\SearchApi;
use Cloudinary\Api\Upload\UploadApi;
use Cloudinary\Asset\File;
Expand Down Expand Up @@ -164,6 +165,16 @@ public function searchApi()
return new SearchApi($this->configuration);
}

/**
* Creates a new SearchFoldersApi instance using the current configuration instance.
*
* @return SearchFoldersApi
*/
public function searchFoldersApi()
{
return new SearchFoldersApi($this->configuration);
}

/**
* Creates a new object and imports current instance configuration.
*
Expand Down
33 changes: 33 additions & 0 deletions tests/Helpers/MockSearchFoldersApi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?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\Helpers;

use Cloudinary\Api\Search\SearchFoldersApi;

/**
* Class MockSearchFoldersApi
*/
class MockSearchFoldersApi extends SearchFoldersApi
{
use MockApiTrait;

/**
* MockSearchFoldersApi constructor.
*
* @param mixed $configuration
*/
public function __construct($configuration = null)
{
parent::__construct($configuration);

$this->apiClient = new MockApiClient($configuration);
}
}
63 changes: 46 additions & 17 deletions tests/Integration/Search/SearchApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@

use Cloudinary\Api\Exception\ApiError;
use Cloudinary\Api\Exception\BadRequest;
use Cloudinary\Api\Search\SearchFoldersApi;
use Cloudinary\Api\Search\SearchApi;
use Cloudinary\Cloudinary;
use Cloudinary\Test\Integration\IntegrationTestCase;
use Cloudinary\StringUtils;
use Cloudinary\Transformation\Scale;
Expand All @@ -28,16 +30,26 @@ class SearchApiTest extends IntegrationTestCase
const SEARCH_ASSET_2 = 'search_asset_2';
const SEARCH_ASSET_3 = 'search_asset_3';

const FOLDER_BASE_NAME = 'test_folder';

private static $STRING_WITH_UNDERSCORE;
private static $STRING_1;
private static $STRING_2;
private static $MULTI_STRING;

private static $FOLDER_NAME;
private static $FOLDER2_NAME;

/**
* @var SearchApi
*/
public $search;

/**
* @var SearchFoldersApi
*/
public $searchFolders;

/**
* @throws ApiError
*/
Expand All @@ -47,14 +59,17 @@ public static function setUpBeforeClass()

// Define a number of unique strings to be used in tags and public ids
self::$STRING_WITH_UNDERSCORE = 'expression_' . self::$UNIQUE_TEST_ID;
self::$STRING_1 = '1stString' . self::$SUFFIX;
self::$STRING_2 = '2ndString' . self::$SUFFIX;
self::$MULTI_STRING = self::$STRING_1 . '_' . self::$STRING_2;
self::$STRING_1 = '1stString' . self::$SUFFIX;
self::$STRING_2 = '2ndString' . self::$SUFFIX;
self::$MULTI_STRING = self::$STRING_1 . '_' . self::$STRING_2;

self::$FOLDER_NAME = self::FOLDER_BASE_NAME . '_' . self::$UNIQUE_TEST_ID;
self::$FOLDER2_NAME = self::FOLDER_BASE_NAME . '_2_' . self::$UNIQUE_TEST_ID;

$assets = [
'options' => [
'context' => ['stage' => 'value'],
'eager' => (new Transformation())->resize(Scale::scale(100)),
'eager' => (new Transformation())->resize(Scale::scale(100)),
],
];

Expand All @@ -65,23 +80,26 @@ public static function setUpBeforeClass()
self::SEARCH_ASSET_3 => $assets,
[
'options' => [
'tags' => [self::$STRING_WITH_UNDERSCORE, self::$STRING_1],
'public_id' => self::$STRING_1
'tags' => [self::$STRING_WITH_UNDERSCORE, self::$STRING_1],
'public_id' => self::$STRING_1,
'folder' => self::$FOLDER_NAME,
],
],
[
'options' => [
'tags' => [self::$STRING_2],
'context' => [self::CONTEXT_KEY => self::$STRING_WITH_UNDERSCORE]
'tags' => [self::$STRING_2],
'context' => [self::CONTEXT_KEY => self::$STRING_WITH_UNDERSCORE],
'folder' => self::$FOLDER_NAME,
],
],
[
'options' => [
'tags' => [
'tags' => [
self::$STRING_WITH_UNDERSCORE,
self::$MULTI_STRING
self::$MULTI_STRING,
],
'context' => [self::CONTEXT_KEY => self::$STRING_WITH_UNDERSCORE]
'context' => [self::CONTEXT_KEY => self::$STRING_WITH_UNDERSCORE],
'folder' => self::$FOLDER2_NAME,
],
],
]
Expand All @@ -92,10 +110,9 @@ public static function setUpBeforeClass()
public function setUp()
{
parent::setUp();
// if (!\Cloudinary::config_get('api_secret')) {
// $this->markTestSkipped('Please setup environment for Search test to run');
// }
$this->search = new SearchApi();

$this->search = (new Cloudinary())->searchApi();
$this->searchFolders = (new Cloudinary())->searchFoldersApi();
}

public static function tearDownAfterClass()
Expand Down Expand Up @@ -347,8 +364,8 @@ static function ($a, $b) {
public function testFindAssetsByExpressionWithoutCertainTag()
{
$expression = 'resource_type:image'
. ' AND context.key:' . self::$STRING_WITH_UNDERSCORE
. ' AND -tags:' . self::$STRING_WITH_UNDERSCORE;
. ' AND context.key:' . self::$STRING_WITH_UNDERSCORE
. ' AND -tags:' . self::$STRING_WITH_UNDERSCORE;

try {
$result = $this->search
Expand All @@ -368,4 +385,16 @@ public function testFindAssetsByExpressionWithoutCertainTag()
self::assertCount(1, $result['resources']);
self::assertValidAsset($result['resources'][0]);
}

public function testSearchFoldersApi()
{
$result = $this->searchFolders
->expression(self::FOLDER_BASE_NAME . '*')
->maxResults(2)
->execute();

self::assertGreaterThan(1, $result['total_count']);
self::assertCount(2, $result['folders']);
self::assertStringContainsString(self::FOLDER_BASE_NAME, $result['folders'][0]['name']);
}
}
17 changes: 17 additions & 0 deletions tests/Unit/Search/SearchApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace Cloudinary\Test\Unit\Search;

use Cloudinary\Api\Exception\GeneralError;
use Cloudinary\Test\Helpers\MockSearchFoldersApi;
use Cloudinary\Test\Helpers\MockSearchApi;
use Cloudinary\Test\Helpers\RequestAssertionsTrait;
use Cloudinary\Test\Unit\UnitTestCase;
Expand Down Expand Up @@ -95,4 +96,20 @@ public function testShouldNotDuplicateValues()
]
);
}

public function testShouldSearchFolders()
{
$mockSearchApi = new MockSearchFoldersApi();
$mockSearchApi->expression('parent=folder_name')->execute();

$lastRequest = $mockSearchApi->getMockHandler()->getLastRequest();

self::assertStringEndsWith('folders/search', $lastRequest->getRequestTarget());
self::assertRequestJsonBodySubset(
$lastRequest,
[
'expression' => 'parent=folder_name',
]
);
}
}

0 comments on commit 8087ddb

Please sign in to comment.